Jump to content

Oscis

Members
  • Posts

    13
  • Joined

  • Last visited

Everything posted by Oscis

  1. I am trying to create a re-sizable GUI that has nested tab controls. I know a trick with which to do this is to put the second layer of tabs inside a child GUI and hide and show whatever child GUIs are needed to create the effect of switching from one sub-tab to another. My issue is when I try to resize a child GUI of a child GUI, my script seems to be stuck. Is there a better way to resize child GUIs, and are child GUIs meant to have further GUIs of their own? In my code, I've commented out the line that causes the script to freeze, but I've tried to make it obvious which line that is so that once you see the rest of the script runs as it should, that one additional child GUI being resized causes problems. Uncomment line 50 to see the error. "WinMove($ChildGUI2, "", $tRECT.Left + 30, $tRECT.Top + 30, $GUIWidth - 120, $GUIHeight - 120, 0)" Test Resizing.au3
  2. Where are you getting your data from before it enters the program? Are you going to type the info for all 1,000 computers yourself?
  3. I think things should be kept simple, so here's what I came up with. You press a hotkey to bring up an inputbox, type an equation, and your answer is placed on the clipboard. You can type in numbers followed by the currency, if applicable. gem is gems, g is gold, s is silver, and c is copper, but you don't need to type c after copper if you don't want to. Let's say an item cost 2 gems, 5 gold, 2 silver, and 100 copper, there are 100 in a stack, and I want to buy 5 stacks. To find out how much this costs, I'd type "(2gem + 5g + 2s + 100) * 100 * 5" (without the quotations of course, and press enter. The program outputs the following: "(2gem + 5g + 2s + 100) * 100 * 5 = 1,002 gems, 501 gold, and 50 silver". Just to make sure this program is working properly, you can type "1gem + 1g + 1s + 1", and make sure it is "1 gem, 1 gold, 1 silver, and 1 copper". The program seems to be working well as far as I can tell, so here's the code. #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/RM /SF = 1 /SV = 1 /PE #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** ;#include <array.au3> If HotKeySet("^0", "_GO") = 0 Then MsgBox(262208, "Error", "I was unable to set ^0 as a hotkey, and must close the program. You can change the hotkey, or restart the application to try again.") Exit EndIf Opt("MustDeclareVars", 1) ;Testing purposes only ;_GO() ;Exit While 1 Sleep(1000) WEnd Func _GO() ;1 gem = 1000 gold = 1,000,000,000 copper ;1 gold = 1000 silver = 1,000,000 copper ;1 silver = 1000 copper HotKeySet("^0");Unset the hotkey while the inputbox is showing Local $Input = InputBox("Game Calculator", "Please type in your equation"), $Answer, $Split, $R If @error Then If MsgBox(262180, "Question", "Do you want to close this program?") = 6 Then MsgBox(262144, "Done", "The program has been closed.") Exit EndIf EndIf HotKeySet("^0", "_GO");Reset the hotkey If $Input == "" Then Return;If you hit the cancel button or don't type anything in, then just wait for another hotkey press. Switch StringLeft($Input, 1) Case "r", "R" $R = True Case Else $R = False EndSwitch ;Local $Input = "(1gem + 1g + 1s + 1c) * 1gem" If $R Then $Split = StringSplit($Input, "/");Only / is accepted as a division sign. If $Split[0] = 1 Then Do ClipPut($Input) Until ClipGet() = $Input MsgBox(262208, "Error", $Input & @CRLF & "You asked me to calculate a remainder, but I did not find a division sign.") Return EndIf $Split[1] = StringTrimLeft($Split[1], 1) For $C = 1 To $Split[0] _FormatString($Split[$C]);Just incase you are dividing one currency by another. I may as well not limit the options. ConsoleWrite("$Split[" & $C & "] = " & $Split[$C] & @CR) Next For $C = 3 To $Split[0] $Split[2] = $Split[2] * $Split[$C];Consolidate multiple division operations into one. Next $Answer = $Input & " = " & _ConvertCopper(Floor($Split[1] / $Split[2])) & " with " & _ConvertCopper(Mod($Split[1], $Split[2])) & " remaining." Else $Answer = $Input _FormatString($Answer) ;Convert copper $Answer = $Input & " = " & _ConvertCopper($Answer) EndIf Do ClipPut($Answer) Until ClipGet() = $Answer MsgBox(0, "Answer", $Answer) EndFunc ;==>_GO Func _FormatString(ByRef $Answer) Local $Match, $Offset = 1, $Split ;Convert gems to copper While 1 $Match = StringRegExp($Answer, "(\d+)gem", 1, $Offset) If @error Then ExitLoop EndIf $Offset = @extended $Answer = StringReplace($Answer, $Match[0] & "gem", $Match[0] * 1000000000);10^9 ;_ArrayDisplay($Match,"$Match") ConsoleWrite("$Answer = " & $Answer & @CR) WEnd ;Convert gold to copper $Offset = 1 While 1 $Match = StringRegExp($Answer, "(\d+)g", 1, $Offset) If @error Then ExitLoop EndIf $Offset = @extended $Answer = StringReplace($Answer, $Match[0] & "g", $Match[0] * 1000000);10^6 ;_ArrayDisplay($Match,"$Match") ConsoleWrite("$Answer = " & $Answer & @CR) WEnd ;Convert silver to copper $Offset = 1 While 1 $Match = StringRegExp($Answer, "(\d+)s", 1, $Offset) If @error Then ExitLoop EndIf $Offset = @extended $Answer = StringReplace($Answer, $Match[0] & "s", $Match[0] * 1000);10^3 ;_ArrayDisplay($Match,"$Match") ConsoleWrite("$Answer = " & $Answer & @CR) WEnd ;Remove copper suffix, just in case $Offset = 1 While 1 $Match = StringRegExp($Answer, "(\d+)c", 1, $Offset) If @error Then ExitLoop EndIf $Offset = @extended $Answer = StringReplace($Answer, $Match[0] & "c", $Match[0]);10^3 ;_ArrayDisplay($Match,"$Match") ConsoleWrite("$Answer = " & $Answer & @CR) WEnd $Offset = 1 ;Add addition signs where reasonable While 1 $Match = StringRegExp($Answer, "(\d+ \d+)", 1, $Offset) If @error Then ExitLoop EndIf $Offset = @extended $Split = StringSplit($Match[0], " ", 2) $Answer = StringReplace($Answer, $Match[0], $Split[0] & " + " & $Split[1]) WEnd $Answer = Execute($Answer);Calculate copper EndFunc ;==>_FormatString Func _ConvertCopper($Copper);I know there's a more efficient way to do this, so I'll type some faster code later. ;Check if this is a decimal ;If Int($Copper) < $Copper Then Local $Gems, $Gold, $Silver, $Array[4], $Count = -1, $Text = "" If $Copper > 999999999 Then;10^9 - 1 $Count = 0 $Array[$Count] = Floor($Copper / 1000000000) $Copper = Mod($Copper, 1000000000) If $Array[$Count] > 1 Then $Array[$Count] = _AddCommasInt($Array[$Count]) & " gems" Else $Array[$Count] = _AddCommasInt($Array[$Count]) & " gem" EndIf EndIf If $Copper > 999999 Then;10^6 - 1 $Count += 1 $Array[$Count] = Floor($Copper / 1000000) & " gold" $Copper = Mod($Copper, 1000000) EndIf If $Copper > 999 Then;10^3 - 1 = 999 $Count += 1 $Array[$Count] = Floor($Copper / 1000) & " silver" $Copper = Mod($Copper, 1000) EndIf If $Count > 0 Then If $Copper Then For $C = 0 To $Count $Text &= $Array[$C] & ", " Next $Text &= " and " & $Copper & " copper" Else Local $CMax = $Count - 1 For $C = 0 To $CMax $Text &= $Array[$C] & ", " Next $Text &= " and " & $Array[$Count] EndIf Else If $Copper Then $Text = $Copper & " copper" Else $Text = $Array[$Count] EndIf EndIf Return $Text EndFunc ;==>_ConvertCopper Func _AddCommasInt($N);Don't check if the number has a decimal because we know it'll be an intiger Local $E = StringLen($N) - 3, $S, $T If $E > 0 Then $S = Mod($E, 3) If $S Then $T = StringLeft($N, $S) & "," Else $T = "" EndIf $S += 1 For $C = $S To $E Step 3 $T &= StringMid($N, $C, 3) & "," Next $T &= StringMid($N, $E + 1) Return $T Else Return $N EndIf EndFunc ;==>_AddCommasInt You can compile this to make the program even more efficient than it already is. The Directives at the top of the script will run AU3Stripper before the program is compiled. If you have trouble typing in a calculation, explain what you're trying to calculate, and I'll see if I can show you the equation. I'm sure you'll figure it out though. Addition signs are optional. I can type "1gem 1g 1s 1c" or "1gem 1g 1s 1" and I get "1 gem, 1 gold, 1 silver, and 1 copper". If you want something other than an addition sign between two values, you'll have to type in the sign. I also added an option to calculate a remainder. Type "R" or "r" before your equation to do this. For example: "r50g/3" is "16 gold, 666 silver, and 666 copper with 2 copper remaining." Multiple divisions work as well. "1 gold, 851 silver, and 851 copper with 23 copper remaining." Let me know what you think, and if there's something you'd like to add, feel free to explain your idea.
  4. You can look at the code inside the functions you want to use and remove only the parts you need. This is taken from _ComputerGetProcessors. For example, you could easily save any of these values to a variable: Opt("MustDeclareVars",1) Local $objWMIService = ObjGet("winmgmts:\\" & @ComputerName & "\root\CIMV2"), $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_Processor", "WQL", 0x30), $objItem For $objItem In $colItems ConsoleWrite($objItem.AddressWidth & @CR) ConsoleWrite($objItem.Architecture & @CR) ConsoleWrite($objItem.Availability & @CR) ConsoleWrite($objItem.Description & @CR) ConsoleWrite($objItem.ConfigManagerErrorCode & @CR) ConsoleWrite($objItem.ConfigManagerUserConfig & @CR) ConsoleWrite($objItem.CpuStatus & @CR) ConsoleWrite($objItem.CreationClassName & @CR) ConsoleWrite($objItem.CurrentClockSpeed & @CR) ConsoleWrite($objItem.CurrentVoltage & @CR) ConsoleWrite($objItem.DataWidth & @CR) ConsoleWrite($objItem.DeviceID & @CR) ConsoleWrite($objItem.ErrorCleared & @CR) ConsoleWrite($objItem.ErrorDescription & @CR) ConsoleWrite($objItem.ExtClock & @CR) ConsoleWrite($objItem.Family & @CR) ConsoleWrite($objItem.L2CacheSize & @CR) ConsoleWrite($objItem.L2CacheSpeed & @CR) ConsoleWrite($objItem.LastErrorCode & @CR) ConsoleWrite($objItem.Level & @CR) ConsoleWrite($objItem.LoadPercentage & @CR) ConsoleWrite($objItem.Manufacturer & @CR) ConsoleWrite($objItem.MaxClockSpeed & @CR) ConsoleWrite($objItem.OtherFamilyDescription & @CR) ConsoleWrite($objItem.PNPDeviceID & @CR) ConsoleWrite($objItem.PowerManagementCapabilities(0) & @CR) ConsoleWrite($objItem.PowerManagementSupported & @CR) ConsoleWrite($objItem.ProcessorId & @CR) ConsoleWrite($objItem.ProcessorType & @CR) ConsoleWrite($objItem.Revision & @CR) ConsoleWrite($objItem.Role & @CR) ConsoleWrite($objItem.SocketDesignation & @CR) ConsoleWrite($objItem.Status & @CR) ConsoleWrite($objItem.StatusInfo & @CR) ConsoleWrite($objItem.Stepping & @CR) ConsoleWrite($objItem.SystemCreationClassName & @CR) ConsoleWrite($objItem.SystemName & @CR) ConsoleWrite($objItem.UniqueId & @CR) ConsoleWrite($objItem.UpgradeMethod & @CR) ConsoleWrite($objItem.Version & @CR) ConsoleWrite($objItem.VoltageCaps & @TAB & @CR) Next
  5. #Include <array.au3> Opt("MustDeclareVars",1) Local $a1 = '1|2' Local $ab1 = StringSplit($a1, "|",2) _ArrayDisplay($ab1) Local $b1 = '3|4' Local $ab2 = StringSplit($b1, "|",2) _ArrayDisplay($ab2) Local $c1 = _CombineArrays($ab1, $ab2) _ArrayDisplay($c1) Func _CombineArrays(ByRef $Array, ByRef $Array2) Local $CMax = UBound($Array) Local $Array3[$CMax][2] $CMax -= 1 For $C = 0 to $CMax $Array3[$C][0] = $Array[$C] $Array3[$C][1] = $Array2[$C] Next Return $Array3 EndFunc I noticed czardas' code after I already typed this up. He does in fact have the most efficient solution. I decided to post what I had anyway, in case you wanted to see a more general implementation.
  6. A while back I was working on some functions for autosized labels (both width and height given some parameters), and progress bars that changed from red to green from 0 to 100% over a gradient. It worked, but I think I can make it more efficient. To autosize the label, I called GUICtrlCreateLabel() many times and obtained the size of the resulting label as part of the calculations. Does anyone know how to create labels and progress bars without calling the built in autoit functions? Maybe if I could look at the actual DLLs, I'll see another way to do this. I know msgbox() can be replaced with DLL calls, which is why I ask if these built in functions are simply calling DLLs with preset parameters. I've looked at Melba's autosize UDF, but calling GUICtrlCreateLabel() and measuring that is accurate to a single pixel, where as the GDI functions sometimes differ compared to the way a label seems to display the same text. Any help is appreciated.
  7. Here's my attempt at it. Is this script any faster than what you have? #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/RM /SF = 1 /SV = 1 /PE #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** Opt("MustDeclareVars",1) Opt("GUIOnEventMode", 1);Turn on GUIOnEventMode #include <Excel.au3> #include <Array.au3> #include <StaticConstants.au3> #include <ProgressConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Local $oExcelFilePath = @ScriptDir & "\Template.xlsx" _CreateExcelWorkbook($oExcelFilePath);You already have your workbook. Local $Array = _CreateArray();You already have an array of course. _UpdateExcelWorkbook($Array,$oExcelFilePath) Func _CreateExcelWorkbook($oExcelFilePath) Local $oExcel = ObjCreate("Excel.Application") $oExcel.Visible = True $oExcel.WorkBooks.Add() $oExcel.ActiveWorkbook.Sheets(1).Select() $oExcel.ActiveWorkBook.SaveAs($oExcelFilePath,51, "", "", Default, Default, 1, 2);(FilePath,VType,ReadPassword,$WritePassword,$AccessMode,$ConflictResolution) ;51 is xlsx $oExcel.Application.Quit() EndFunc Func _CreateArray() Local $Array[8001][9] For $C = 1 to 8000;8,000 rows. For $C2 = 1 to 8;8 collumns A to H, right? $Array[$C][$C2] = Random(1,9,1)/10 Next Next Return $Array EndFunc Func _UpdateExcelWorkbook(ByRef $Array, $oExcelFilePath) Local $Timer = TimerInit() Global $oExcel = ObjCreate("Excel.Application") $oExcel.Visible = False;Hide the workbook. It won't update anyway. $oExcel.WorkBooks.Open($oExcelFilePath, Default, False, Default, "", "");($FilePath, Unknown, $ReadOnly, Unknown, $ReadPassword, $WritePassword) $oExcel.ActiveWorkbook.Sheets(1).Select() $oExcel.Application.ScreenUpdating = False;Turn off screen updating to speed things up Global Const $CMax = UBound($Array,1) - 1, $MaxCollumns = _AddCommas($CMax) Global $Percent, $C Local Const $C2Max = UBound($Array,2) - 1 AdlibRegister("_Progress",2500);Update every 2.5 seconds. This can be shortened down to 1/4 of a second, but calling a function pauses the rest of the script until that function is done. Local $GUI = GUICreate("Grey Out Excel Rows",400,100,-1,-1,$WS_CAPTION) Global $ProgressControl = GUICtrlCreateProgress(10,10,380,20,$PBS_SMOOTH), $ProgressLabel = GUICtrlCreateLabel("0%",10,40,380,20,$SS_CENTER), _ $StatusLabel = GUICtrlCreateLabel("Write Data to Excel - Row 0 of " & $MaxCollumns,10,70,380,20,$SS_CENTER) GUISetState() GUISetOnEvent($GUI_EVENT_CLOSE, "_GUIClose") ;Write data to Excel Do $C += 1 For $C2 = 1 to $C2Max;Collumns $oExcel.Sheets(1).Cells($C,$C2).Value = $Array[$C][$C2] Next Until $C = $CMax AdlibUnRegister("_Progress") GUICtrlSetData($ProgressControl,0) GUICtrlSetData($ProgressLabel,"0%") GUICtrlSetData($StatusLabel,"Grey out cells - Row 0 of " & $MaxCollumns) AdlibRegister("_Progress2",2500) ;Grey out rows $C = 0 Do $C += 1 If $oExcel.Sheets(1).Cells($C,1).Value = 0.1 Then $oExcel.ActiveSheet.Range("A" & $C & ":H" & $C).Interior.ColorIndex = 15 Until $C = $CMax AdlibUnRegister("_Progress2") GUIDelete($GUI) GUISetOnEvent($GUI_EVENT_CLOSE,"");Unregister this event ProgressOff() ;$oExcel.DisplayAlerts = False;Without this, Excel asks to save your work. $oExcel.Visible = True;Show the workbook so that you can close it if it doesn't close on its own. $oExcel.Application.ScreenUpdating = True;Turn Screen Updating back on $oExcel.ActiveWorkBook.Save() $oExcel.Application.Quit() $oExcel = 0;Free memory $Timer = Round(TimerDiff($Timer)/1000,2) ;$oExcel.Quit();Does the same thing 0.o ShellExecute($oExcelFilePath);Close Excel, then re-launch it to make sure it saved properly MsgBox(0,"Done","I've finished updating your spreadsheet, and opened the file for you to view." & @CRLF & @CRLF & "The process took " & _FormatMiliseconds($Timer) & ".") EndFunc Func _Progress() $Percent = Round($C/$CMax*100,2) GUICtrlSetData($ProgressControl,$Percent) GUICtrlSetData($ProgressLabel,$Percent & "%") GUICtrlSetData($StatusLabel,"Write Data to Excel - Row " & $C & " of " & $MaxCollumns) ProgressSet($Percent,$Percent & "%","Row " & _AddCommas($C) & " of " & $MaxCollumns) EndFunc Func _Progress2() $Percent = Round($C/$CMax*100,2) GUICtrlSetData($ProgressControl,$Percent) GUICtrlSetData($ProgressLabel,$Percent & "%") GUICtrlSetData($StatusLabel,"Grey out cells - Row " & $C & " of " & $MaxCollumns) ProgressSet($Percent,$Percent & "%","Row " & _AddCommas($C) & " of " & $MaxCollumns) EndFunc Func _GUIClose() If MsgBox(262180,"Question","Are you sure you want to exit the program?") = 6 Then;4 + 32 + 262144 = 262180 Yes and No buttons, question mark and topmost attribute. $oExcel.DisplayAlerts = False;Without this, Excel asks to save your work. $oExcel.Application.ScreenUpdating = True;Turn Screen Updating back on $oExcel.Application.Quit() $oExcel = 0;Free memory Exit EndIf EndFunc Func _AddCommas($N) Local $D = StringInStr($N,".",2), $E, $S, $T If $D Then $E = $D - 4 Else $E = StringLen($N) - 3 EndIf If $E > 0 Then $S = Mod($E,3) If $S Then $T = StringLeft($N,$S) & "," Else $T = "" EndIf $S += 1 For $C = $S to $E Step 3 $T &= StringMid($N,$C,3) & "," Next $T &= StringMid($N,$E + 1) Return $T Else Return $N EndIf EndFunc Func _FormatMiliseconds($N,$P = 2) Local $D, $H, $M, $S, $T;Declaring every variable at the beginning proved to be faster than declaring the variables only when they're needed. If $N > 86400000 Then;24*60*60*1000 = 86400000 1 Day $D = Floor($N/86400000) $N = Mod($N,86400000) If $N > 3600000 Then;60 * 60 * 1000 = 3600000 1 Hour $H = Floor($N/3600000) $N = Mod($N,3600000) If $N > 60000 Then ;60 * 1000 = 60000 1 Minute $M = Floor($N/60000) $N = Mod($N,60000) If $N > 0 Then ;1 Second $S = Round($N/1000,$P) If $D > 1 Then $T = $D & " days, " Else $T = "1 day, " EndIf If $H > 1 Then $T &= $H & " hours, " Else $T &= "1 hour, " EndIf If $M > 1 Then $T &= $M & " minutes, and " Else $T &= "1 minute, and " EndIf If $S = 1 Then $T &= "1 second" Else $T &= $S & " seconds" EndIf Return $T;1111 Else If $D > 1 Then $T = $D & " days, " Else $T = "1 day, " EndIf If $H > 1 Then $T &= $H & " hours, and " Else $T &= "1 hour, and " EndIf If $M > 1 Then $T &= $M & " minutes" Else $T &= "1 minute" EndIf Return $T;1110 EndIf Else If $N > 0 Then ;1 Second $S = Round($N/1000,$P) If $D > 1 Then $T = $D & " days, " Else $T = "1 day, " EndIf If $H > 1 Then $T &= $H & " hours, and " Else $T &= "1 hour, and " EndIf If $S = 1 Then $T &= "1 second" Else $T &= $S & " seconds" EndIf Return $T;1101 Else If $D > 1 Then $T = $D & " days, and " Else $T = "1 day, and " EndIf If $H > 1 Then $T &= $H & " hours" Else $T &= "1 hour" EndIf Return $T;1100 EndIf EndIf Else If $N > 60000 Then ;60 * 1000 = 60000 1 Minute $M = Floor($N/60000) $N = Mod($N,60000) If $N > 0 Then ;1 Second $S = Round($N/1000,$P) If $D > 1 Then $T = $D & " days, " Else $T = "1 day, " EndIf If $M > 1 Then $T &= $M & " minutes, and " Else $T &= "1 minute, and " EndIf If $S = 1 Then $T &= "1 second" Else $T &= $S & " seconds" EndIf Return $T;1011 Else If $D > 1 Then $T = $D & " days and " Else $T = "1 day and " EndIf If $M > 1 Then $T &= $M & " minutes" Else $T &= "1 minute" EndIf Return $T;1010 EndIf Else If $N > 0 Then ;1 Second $S = Round($N/1000,$P) If $D > 1 Then $T = $D & " days and " Else $T = "1 day and " EndIf If $S = 1 Then $T &= "1 second" Else $T &= $S & " seconds" EndIf Return $T;1001 Else If $D > 1 Then Return $D & " days" Else Return "1 day" EndIf ;1000 EndIf EndIf EndIf Else If $N > 3600000 Then;60 * 60 * 1000 = 3600000 1 Hour $H = Floor($N/3600000) $N = Mod($N,3600000) If $N > 60000 Then ;60 * 1000 = 60000 1 Minute $M = Floor($N/60000) $N = Mod($N,60000) If $N > 0 Then ;1 Second $S = Round($N/1000,$P) If $H > 1 Then $T = $H & " hours, " Else $T = "1 hour, " EndIf If $M > 1 Then $T &= $M & " minutes, and " Else $T &= "1 minute, and " EndIf If $S = 1 Then $T &= "1 second" Else $T &= $S & " seconds" EndIf Return $T;0111 Else If $H > 1 Then $T = $H & " hours and " Else $T = "1 hour and " EndIf If $M > 1 Then $T &= $M & " minutes" Else $T &= "1 minute" EndIf Return $T;0110 EndIf Else If $N > 0 Then ;1 Second $S = Round($N/1000,$P) If $H > 1 Then $T = $H & " hours and " Else $T = "1 hour and " EndIf If $S = 1 Then $T &= "1 second" Else $T &= $S & " seconds" EndIf Return $T;0101 Else If $H > 1 Then Return $H & " hours" Else Return "1 hour" EndIf ;0100 EndIf EndIf Else If $N > 60000 Then ;60 * 1000 = 60000 1 Minute $M = Floor($N/60000) $N = Mod($N,60000) If $N > 0 Then ;1 Second $S = Round($N/1000,$P) If $M > 1 Then $T = $M & " minutes and " Else $T = "1 minute and " EndIf If $S = 1 Then $T &= "1 second" Else $T &= $S & " seconds" EndIf Return $T;0011 Else If $M > 1 Then Return $M & " minutes" Else Return "1 minute" EndIf ;0010 EndIf Else If $N > 0 Then ;1 Second $S = Round($N/1000,$P) If $S = 1 Then Return "1 second" Else Return $S & " seconds" EndIf ;0001 Else Return "0 seconds" ;0000 EndIf EndIf EndIf EndIf EndFunc I have some functions thrown in there for adding commas to numbers and milliseconds to days, hours, minutes, and seconds. If you compile this script it may run faster because of the way the AU3Stripper is set up. The translator will have shorter variable names to work with, which generally speeds up a program, but sometimes the change isn't drastic.
  8. What is the maximum number of columns that is in any row? Do you have any blank cells in a row, or does the row end at a blank cell? The answer to these questions may help limit how much of the document has to be read, which will speed up the program. I'll type up some code with some made up ranges as an example. Edit: I took a closer look at your code, and I think I have the answers to my own questions.
  9. I'm working on a second version of this program now. I'll see what I can do.
  10. I made a script that splits a file in binary or normal mode. You can use an interface, or just integrate the function into another script. If you use the interface, you can drag a file into the first input control to get the file path, and drag a folder into the second input control to set the destination folder for the resulting files. You can type in a prefix that all the resulting files will share in the 3rd input control, and the delimiter you want to use the split the file in the 4th input control. If you leave the 2nd and 3rd input controls blank, the program will fill in default values based on the given file path. If you have any suggestions, or find bugs, let me know. Here is the code: #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/RM /SF = 1 /SV = 1 /PE #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** Opt("MustDeclareVars",1) ;These includes are only needed for the interface. #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <StaticConstants.au3> ;_Example1() _Example2() Func _Example1();Splitting a file without a user interface Local $FileName = "" Local $Folder = "" Local $Prefix = "" Local $Delimiter = "****** END OF REPORT ******" ;_SplitFileHex($FileName,$Folder,$Prefix,$Delimiter) _SplitFile($FileName,$Folder,$Prefix,$Delimiter) EndFunc Func _Example2();Splitting a file with a user interface Local $GUI = GUICreate("File Splitter",300,130,-1,-1,-1,$WS_EX_ACCEPTFILES) Local $Label = GUICtrlCreateLabel("File:",10,10,68,20,$SS_RIGHT) GUICtrlSetFont($Label,12) Local $Input = GUICtrlCreateInput("",88,10,202,20) Local $Label2 = GUICtrlCreateLabel("Folder:",10,40,68,20,$SS_RIGHT) GUICtrlSetFont($Label2,12) Local $Input2 = GUICtrlCreateInput("",88,40,202,20) Local $Label3 = GUICtrlCreateLabel("Prefix:",10,70,68,20,$SS_RIGHT) GUICtrlSetFont($Label3,12) Local $Input3 = GUICtrlCreateInput("",88,70,202,20) Local $Label4 = GUICtrlCreateLabel("Delimiter:",10,100,68,20,$SS_RIGHT) GUICtrlSetFont($Label4,12) Local $Input4 = GUICtrlCreateInput("",88,100,202,20) Local $NextButton = GUICtrlCreateButton("",0,0,0,0) GUICtrlSetState($NextButton,$GUI_HIDE) Local $GUIAccelerators[1][2] = [["{ENTER}",$NextButton]] GUISetAccelerators($GUIAccelerators,$GUI) GUICtrlSetState($Input,$GUI_DROPACCEPTED) GUICtrlSetState($Input2,$GUI_DROPACCEPTED) GUISetState() Local $File, $FileName, $Prefix, $Delimiter, $A, $B, $Folder, $Text, $Continue = True While 1 Switch GUIGetMsg() Case -3 ExitLoop Case $NextButton $FileName = GUICtrlRead($Input) If $FileName == "" Then MsgBox(0,"Error","You must type in a file name, or drag a file into the first input box before you continue.") ElseIf FileExists($FileName) Then ConsoleWrite($FileName & @CR) $A = StringInStr($FileName,"\",0,-1) $Folder = GUICtrlRead($Input2) $Continue = True If $Folder == "" Then $Folder = StringLeft($FileName,$A) GUICtrlSetData($Input2,$Folder) $Continue = False ConsoleWrite($Folder & @CR) EndIf $Prefix = GUICtrlRead($Input3) If $Prefix == "" Then $A += 1 $B = StringInStr($FileName,".",0,-1) ConsoleWrite($A & @CR & $B & @CR & StringLen($FileName) & @CR) $Prefix = StringMid($FileName,$A,$B - $A) GUICtrlSetData($Input3,$Prefix) $Continue = False EndIf If $Continue Then $Delimiter = GUICtrlRead($Input4) ConsoleWrite("$Delimiter = " & $Delimiter & @CR) If $Delimiter == "" Then MsgBox(0,"Error","You did not type in a delimiter. Where do you want this program to split the file?") Else If MsgBox(4,"Question","Do you want to open the file in binary mode?") = 6 Then _SplitFileHex($FileName,$Folder,$Prefix,$Delimiter) Else _SplitFile($FileName,$Folder,$Prefix,$Delimiter) EndIf EndIf EndIf Else MsgBox(0,"Error","I could not find the file. Please check the file path, and try again.") EndIf EndSwitch WEnd Exit EndFunc Func _SplitFileHex($FileName,$Folder,$Prefix,$Delimiter);The main function, Hex version ProgressOn("File Splitter","Processing Your File","0%",-1,-1,18) Local $File = FileOpen($FileName,16), $Text = FileRead($File) FileClose($File) Local $TextLen = StringLen($Text) If StringRight($Folder,1) <> "\" Then $Folder &= "\" DirCreate($Folder) If StringLeft($Delimiter,2) <> "0x" Then $Delimiter = StringToBinary($Delimiter) $Delimiter = StringTrimLeft($Delimiter,2) Local $Suffix = StringMid($FileName,StringInStr($FileName,".")) $FileName = $Folder & $Prefix & " - " Local $DelimiterLen = StringLen($Delimiter), $String = "", $Start = 3, $End, $Count Local $F = 0, $Percent While 1 $F += 1 $End = StringInStr($Text,$Delimiter,2,1,$Start) If $End Then $End += $DelimiterLen $File = FileOpen($FileName & $F & $Suffix, 26) $Count = $End - $Start FileWrite($File,"0x" & StringMid($Text,$Start,$Count)) FileClose($File) $Start += $Count $Percent = Round(($Start/$TextLen)*100,2) ProgressSet($Percent,$Percent & "%","File " & $F) Else ExitLoop EndIf WEnd ProgressSet(100,"100%","Done!") ProgressOff() MsgBox(0,"Done","I've split your file.") EndFunc Func _SplitFile($FileName,$Folder,$Prefix,$Delimiter);The main function ProgressOn("File Splitter","Processing Your File","0%",-1,-1,18) Local $File = FileOpen($FileName), $Text = FileRead($File) FileClose($File) Local $TextLen = StringLen($Text) If StringRight($Folder,1) <> "\" Then $Folder &= "\" DirCreate($Folder) Local $Suffix = StringMid($FileName,StringInStr($FileName,".")) $FileName = $Folder & $Prefix & " - " Local $DelimiterLen = StringLen($Delimiter), $String = "", $Start = 1, $End, $Count Local $F = 0, $Percent While 1 $F += 1 $End = StringInStr($Text,$Delimiter,1,1,$Start) If $End Then $End += $DelimiterLen $File = FileOpen($FileName & $F & $Suffix, 26) $Count = $End - $Start FileWrite($File,StringMid($Text,$Start,$Count)) FileClose($File) $Start += $Count $Percent = Round(($Start/$TextLen)*100,2) ProgressSet($Percent,$Percent & "%","File " & $F) Else ExitLoop EndIf WEnd ProgressSet(100,"100%","Done!") ProgressOff() MsgBox(0,"Done","I've split your file.") EndFunc Let me know what you think.
  11. Here's my go at it. I have a script that does format the new array properly, and I've included _ArrayDisplay() functions so you can see the starting array and ending array to easily verify that this does what you wanted. This script can be faster if I knew more about the data you are working with. First I'll show you the code: #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/RM /SF = 1 /SV = 1 /PE #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** Opt("MustDeclareVars",1) #include <array.au3> Local Const $Array[6][3] = [[1,"a",2],[2,"b",1],[2,"c",1],[3,"d",2],[1,"e",1],[2,"f",2]] _ArrayDisplay($Array,"$Array") Local $NewArray = _ExpandDuplicates($Array) _ArrayDisplay($NewArray,"$NewArray") Func _ExpandDuplicates(ByRef Const $Array) Local Const $LevelsString = "ghi", $Zeros = "0000000000000000" Local $Rows = UBound($Array) - 1, $String = "", $Binary = "", $PreviousLevel, $C2End, $CountElements[4] #Region Convert this array to a string For $C = 0 to $Rows $CountElements[$Array[$C][0]] += 1;Count how many elements are in each level If $Array[$C][0] <= $PreviousLevel Then $C2End = $Array[$C][0] For $C2 = $PreviousLevel to $C2End Step - 1 $String &= StringMid($LevelsString,$C2,1) Next EndIf $Binary = StringFormat("%x",Hex($Array[$C][2],4)) $String &= StringMid($LevelsString,$Array[$C][0],1) & StringLeft($Zeros,4 - StringLen($Binary)) & $Binary $Binary = StringFormat("%x",StringToBinary($Array[$C][1])) $String &= StringLeft($Zeros,16 - StringLen($Binary)) & $Binary $PreviousLevel = $Array[$C][0] Next ;Close any levels For $C = $PreviousLevel to 1 Step -1 $String &= StringMid($LevelsString,$C,1) Next #EndRegion Convert this array to a string ;ConsoleWrite($String & @CR) #Region Get the maximum number of elements in a level Local $Max = 0 For $C = 1 to 3 If $CountElements[$C] > $Max Then $Max = $CountElements[$C];Get the maximum value Next #EndRegion Get the maximum number of elements in a level #Region Expand the string Local $Match, $Offset, $ReplacementString, $Duplicate, $C2Max, $Replacements[$Max + 1], $Replacements2[$Max], $C3 For $C = 3 to 1 step -1 $C3 = -1 $Offset = 1 While 1 $Match = StringRegExp($String,StringMid($LevelsString,$C,1) & "(.*?)" & StringMid($LevelsString,$C,1),1,$Offset) $Offset = @Extended If @Error Then ExitLoop EndIf $Duplicate = Int("0x" & StringLeft($Match[0],4)) If $Duplicate > 1 Then $Match[0] = StringMid($LevelsString,$C,1) & $Match[0] & StringMid($LevelsString,$C,1) $ReplacementString = $Match[0] $C2Max = Floor(log($Duplicate)/log(2)) For $C2 = 1 to $C2Max $ReplacementString &= $ReplacementString Next ;ConsoleWrite("$Duplicate = " & $Duplicate & @CR & "$C2Max = " & $C2Max & @CR & "$C2Max = " & $C2Max & @CR) $C2Max = $Duplicate - 2 ^ $C2Max For $C2 = 1 to $C2Max $ReplacementString &= $Match[0] Next ;ConsoleWrite($ReplacementString & @CR) $C3 += 1 $Replacements[$C3] = $Match[0] $Replacements2[$C3] = $ReplacementString EndIf ;_ArrayDisplay($Match,"$Match: " & StringMid($LevelsString,$C,1)) WEnd ;_ArrayDisplay($Replacements,"$Replacements, $C2 = " & $C2) For $C2 = 0 to $C3 $String = StringReplace($String,$Replacements[$C2],$Replacements2[$C2]) ;ConsoleWrite($String & @CR) Next Next ;ConsoleWrite($String & @CR) #EndRegion Expand the string #Region Convert the string back into an array ;Count how many elements are in each level to figure out how many elements we need total Local $CMax = 0 For $C = 1 to 3 StringReplace($String,StringMid($LevelsString,$C,1),"") Local $Replacements = @Extended If $Replacements Then $CMax += $Replacements Next $CMax = $CMax/2 Local $NewArray[$CMax][3] ;ConsoleWrite("$Elements = " & $CMax & @CR) $CMax -= 1 $C2 = 1 Local $Skip = 0 For $C = 0 to $CMax $C3 = $C2 While 1;Skip redundant level markers $C3 += 1 If StringInStr($LevelsString,StringMid($String,$C3,1)) Then $C2 = $C3 Else ExitLoop EndIf WEnd $NewArray[$C][0] = StringInStr($LevelsString,StringMid($String,$C2,1)) ;ConsoleWrite(StringMid($String,$C2,1) & @TAB) $C2 += 1 $NewArray[$C][2] = Int("0x" & StringMid($String,$C2,4)) ;ConsoleWrite(StringMid($String,$C2,4) & @TAB) $C2 += 4 $NewArray[$C][1] = BinaryToString("0x" & StringReplace(StringMid($String,$C2,16),"00","")) ;ConsoleWrite(StringMid($String,$C2,16) & @CR) $C2 += 16 Next Return $NewArray #EndRegion Convert the string back into an array EndFunc ;This can support up to 46 levels. They will be represented by the letts g - Z ;Each entry will be represented by 16 hexadecimal characters. This means it can be up to 8 characters long. ;Each quantity will be represented by 4 hexadecimal characters. This means it can represent a number from 0 to 65535 #cs Reserved characters 0 1 2 3 4 5 6 7 8 9 a b c d e f Characters for levels g - 1 h - 2 i - 3 j - 4 k - 5 l - 6 m - 7 n - 8 o - 9 p - 10 q - 11 r - 12 s - 13 t - 14 u - 15 v - 16 w - 17 x - 18 y - 19 z - 20 A - 21 B - 22 C - 23 D - 24 E - 25 F - 26 G - 27 H - 28 I - 29 J - 30 K - 31 L - 32 M - 33 N - 34 O - 35 P - 36 Q - 37 R - 38 S - 39 T - 40 U - 41 V - 42 W - 43 X - 44 Y - 45 Z - 46 #ce Reserved Characters First question: How many levels will the data you're working with use? This script can work for up to 46 levels, but that's probably overkill. If you need < 21 levels, then I can use all upercase letters, and get rid of stringformat(). I can also use a basic comparison for StringinStr and StringReplace. 2) How many characters long are the component names, at maximum? This script can accept input up to 8 characters, but this may be too short. I can increase the length, but this will make the final string the program uses longer, so it's a good idea to get close, but save maximum allowable length. 3) How many of any given item do you expect to ever have? The maximum value that can be in collumn 3 is 65,535, which is probably overkill. If we lower this number, the resulting string the program uses will be shorter. 4) This is a very small array to test this with. I'm sure you can't show me the actual data you're working with, but can you describe the data more? You mentioned it's 20 collumns, and 8,000 rows. Can you describe what values are in each collumn, or perhaps give a list of components so I can generate a bunch of random data to try this script on? I'd like to make sure this script can work for the real data you're using. This script still needs some work, but it's easy to improve. Let me know what you think.
  12. I necroed this thread because it is the first result in Google. Even though it's a very old post, it might point people who simply do a Google search to find what they're looking for in the right direction. What is the longest time a thread can be dormant and replied to without the reply being considered a necro-post? 6 months?
  13. I googled "Add commas to a number Autoit", and this is the first post on the list of results. After sitting down for a while and trying to come up with the fastest way possible to do this without using stringformat, since I couldn't figure out how to type the format control, this is what I came up with. I made sure this works with decimal numbers, and tried to get some speed statistics for 1 to 15 digit numbers. Autoit puts larger numbers than that in scientific notation, and I don't know how to format the number differently. It's probably another stringformat trick. If you only want the actual function, then just copy what is between func and endfunc. Everything else is just for testing purposes. Anyway, here is the code. I made all the variable names 1 letter long because I've found in the past that long variable names can slow a script down, and whoever uses this code will probably just #include the file in their script, so this code won't be read or changed much, and doesn't need easy to read variable names. On my machine, I was able to format 300,000 numbers in 6.11 seconds, which is 49,083 numbers per second. It looks like my nice tab indents won't show here, and the code isn't colored normally after the end of my comments, but Tidy Autoit Source should make this code easier to read. Opt("MustDeclareVars",1) #CS This is for testing accuracy Local $N For $C = 0 to 14 $N = 10^C ConsoleWrite(_AddCommas($N & ".85") & @CR) ConsoleWrite(_AddCommas($N) & @CR) Next #CE This is for testing accuracy #CS This is for testing speed Local $Timer = TimerInit(), $SMax = 10000 For $S = 1 to $SMax _AddCommas(1.85) _AddCommas(1) _AddCommas(10.85) _AddCommas(10) _AddCommas(100.85) _AddCommas(100) _AddCommas(1000.85) _AddCommas(1000) _AddCommas(10000.85) _AddCommas(10000) _AddCommas(100000.85) _AddCommas(100000) _AddCommas(1000000.85) _AddCommas(1000000) _AddCommas(10000000.85) _AddCommas(10000000) _AddCommas(100000000.85) _AddCommas(100000000) _AddCommas(1000000000.85) _AddCommas(1000000000) _AddCommas(10000000000.85) _AddCommas(10000000000) _AddCommas(100000000000.85) _AddCommas(100000000000) _AddCommas(1000000000000.85) _AddCommas(1000000000000) _AddCommas(10000000000000.85) _AddCommas(10000000000000) _AddCommas(100000000000000.85) _AddCommas(100000000000000) Next $Timer = TimerDiff($Timer)/1000 $SMax = 30 * $SMax ConsoleWrite(_AddCommas($SMax) & " numbers in " & _AddCommas(Round($Timer,2)) & " seconds is " & _AddCommas(Floor($SMax/$Timer)) & " numbers per second." & @CR) #CE This is for testing speed Func _AddCommas($N) Local $D = StringInStr($N,".",2) If $D Then Local $E = $D - 4 Else Local $E = StringLen($N) - 3 EndIf If $E > 0 Then Local $S = Mod($E,3) If $S Then Local $T = StringLeft($N,$S) & "," Else Local $T = "" EndIf $S += 1 For $C = $S to $E Step 3 $T &= StringMid($N,$C,3) & "," Next $T &= StringMid($N,$E + 1) Return $T Else Return $N EndIf EndFunc
×
×
  • Create New...