How do I find what a TextBox's contents will be after pressing Ctrl + Z, before it occurs? - textbox

I am writing a small function that will calculate the contents of a TextBox after the KeyPress event, but during the KeyPress event. I know, it sounds strange. :)
The reason for this is because I have been given a project at work, where I am to fix any errors in a current program.
There is currently a TextBox, which triggers a search on a SQL Server, in the KeyPress event.
This searches for the current contents of the TextBox concatenated with Chr(KeyAscii)
This means that if your TextBox contains Hello and your cursor is at the end of the word it will work correctly, but if you have the o selected and press a it will search for Helloa instead of Hella.
So to correct, this I have come up with the following function
Private Function TextAfterKeyPress(Ctrl As Control, KeyAscii As Integer) As String
Dim strUnSelLeft As String
Dim strUnSelRight As String
Dim strSel As String
Dim strMid As String
With Ctrl
strUnSelLeft = ""
strUnSelRight = ""
strMid = .Text
Select Case KeyAscii
Case 1 ' Ctrl + A
' No change to text
Case 3 ' Ctrl + C
' No change to text
Case 8 ' BackSpace
If .SelStart = 0 Then
' No change to text
Else
If .SelLength = 0 Then
strUnSelLeft = Left(.Text, .SelStart - 1)
strUnSelRight = Right(.Text, Len(.Text) - (.SelStart + .SelLength))
strMid = ""
Else
strUnSelLeft = Left(.Text, .SelStart)
strUnSelRight = Right(.Text, Len(.Text) - (.SelStart + .SelLength))
strMid = ""
End If
End If
Case 9 ' Tab
' No change to text
Case 13 ' Return
' No change to text
Case 22 ' Ctrl + V
strUnSelLeft = Left(.Text, .SelStart)
strUnSelRight = Right(.Text, Len(.Text) - (.SelStart + .SelLength))
strMid = Clipboard.GetText
Case 24 ' Ctrl + X
If .SelLength = 0 Then
' No change to text
Else
strUnSelLeft = Left(.Text, .SelStart)
strUnSelRight = Right(.Text, Len(.Text) - (.SelStart + .SelLength))
strMid = ""
End If
Case 26 ' Ctrl + Z
Case 27 ' Esc
' No Change to text
Case 137, 153, 160, 169, 188, 189, 190, 215, 247 ' Disallowed Chars
' No Change to text
Case 128 To 255 ' Allowed non standard Chars
strUnSelLeft = Left(.Text, .SelStart)
strUnSelRight = Right(.Text, Len(.Text) - (.SelStart + .SelLength))
strMid = Chr(KeyAscii)
Case 32 To 127 ' Standard Printable Chars
strUnSelLeft = Left(.Text, .SelStart)
strUnSelRight = Right(.Text, Len(.Text) - (.SelStart + .SelLength))
strMid = Chr(KeyAscii)
Case Else
End Select
TextAfterKeyPress = strUnSelLeft & strMid & strUnSelRight
End With
End Function
Now for the section where it says "Case 26", it will perform an undo action, and then the search won't work correctly again.
Is there any way to find out what the contents of the TextBox will be when you press Ctrl + Z, but during the KeyPress in which it happens? The KeyPress event fires before the content of the TextBox changes so I would need to find out what is in the Undo buffer so that I can run a correct search.
Can anyone point me in the right direction?

I have worked with textbox APIs a bit ..And i don't think you can deal with its UNDO buffer due to its limitation.. but something you can do is to manually send an UNDO then read the textbox content.
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Const EM_UNDO = &HC7
,
Case 26
KeyAscii = 0
SendMessage .hwnd, EM_UNDO, ByVal 0, ByVal 0
strMid = .Text
If you only need to read the text and not to change it you can send an another UNDO msg to get the text to its previous content.

Related

Xojo Type mismatch error. Expected String, but got Boolean

(I started learning about arrays today.) Edit: I realized the = is apperently causing the error because it's seen as a "compare if equal" vs "assign this".
i don't see which part in the referenced line is causing the error:
'Option 1
Var citylistDE(5) as string
citylistDE(0) ="Genf"
citylistDE(1)="Lausanne"
citylistDE(2)="Bern"
citylistDE(3)="Basel"
citylistDE(4)="Zürich"
citylistDE(5)="St.Gallen"
dim countDe as Integer = citylistDE.LastRowIndex
for i as integer = 0 to countDe
de.Value = de.Value = citylistDE(i) + EndOfLine '<=== THIS LINE ?
next
'Option2
var citylistFR() as string = array("Genève", "Lausanne", "Berne", "Bale", "Zurich", "Sant-Gall")
dim countFR as integer = citylistFR.LastRowIndex
for i as integer = 0 to countFR
fr.Value = fr.Value + citylistFR(i) + EndOFLine
next
i found the error. It was the = between de.Value and citylistDE.
I changed it from = to +.
de.Value = de.Value = citylistDE(i) + EndOfLine
next
to
de.Value = de.Value + citylistDE(i) + EndOfLine
next

Run script if cell change in Google Sheets

I have this code, it works if i run it from Script Editor, but doesnt run when i change the cell to "Send Melding". The script runs until it comes to MailApp.sendEmail, then it stops..
Heres the code :
function onEdit(e) {
var s = SpreadsheetApp.getActiveSheet(), r, colCell;
if(s.getName() === 'SkapOversikt') { //checks that we're on the correct sheet
r = s.getActiveCell();
colCell = r.getColumn();
if(colCell === 1 || colCell === 6) { //checks the column
nextCell = r.offset(0, 0);
if(nextCell.getValue() === 'Send Melding') { //Inneholder "Send Melding", kjør script
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = ss.getActiveCell().getA1Notation();
var row = sheet.getActiveRange().getRow();
var cellvalue = ss.getActiveCell().getValue().toString();
var recipients = sheet.getRange(7, 7).getValue();
var subject = 'Skapoversikt har blitt oppdatert på : '+sheet.getRange(4, 2).getValue();
var body = 'Blåse info på ' + sheet.getRange(4, 2).getValue() + ' har blitt oppdatert. ' + '\n' + '\nFølg link for å se endringer : ' + ss.getUrl() + '\n' + '\n' + 'Melding fra melder : ' + '\n' + '" ' + sheet.getRange(6, 7).getValue() + ' " ' + '\n ' + '\n (Dette er en generert mail fra Google Sheets og vil ikke kunne besvares) ' + '\n' + '\n - AK AS ';
MailApp.sendEmail(recipients, subject, body);
var sheet = SpreadsheetApp.getActive().getSheetByName('SkapOversikt');
sheet.getRange('G6').setValue('Ingen Melding');
sheet.getRange('A6').setValue('Velg');
Browser.msgBox('Takk for det - Meldingen er sendt!' , 'Meldingen er sendt til : '+sheet.getRange(7, 7).getValue()+ '\n' + ' - (Fra epost : )', Browser.Buttons.OK);
}
}
}
}
I don't think you can send emails on a simple onEdit trigger. Try changing the name of your function (e.g: sendMails(e) ) and add an installable trigger by going into Resources > add a trigger > sendMails > from spreadsheet > on Edit.
See if it then works ?

xojo call a method with button

I have the code below in a View method to parse JSON files. The method ContentsOfDictionary accepts the parameters d as Xojo.Core.Dictionary and level as an integer, and returns text.If I use ContentsOfDictionary in an action button, I get this error:
error: Not Enough arguments: got 0, expected at least 1
Here is a link to the test file I am using.
How do I call the method ContentsOfDictionary?
dim dict as Xojo.Core.Dictionary = Xojo.Data.ParseJSON (kJsonData)
const kEOL = &u0A
dim indent as text
for i as integer = 1 to level
indent = indent + " "
next
dim t as text
for each entry as Xojo.Core.DictionaryEntry in dict
t = t + indent + entry.Key + " "
if Xojo.Introspection.GetType( entry.Value ) is nil then
t = t + "nil" + kEOL
else
select case Xojo.Introspection.GetType( entry.Value ).Name
case "Boolean"
t = t + if( entry.Value, "true", "false" ) + kEOL
case "Text"
t = t + entry.Value + kEOL
case "Int32", "Int64"
//
// You get the idea
//
case "Dictionary"
t = t + kEOL + ContentsOfDictionary( entry.Value, level + 1 )
end select
end if
next
return t
UPDATE: None of the below applies as #johnnyB's example was of the ContentsOfDictionary function and should not have been trying to access the JSON data but just working on the supplied Dictionary. There is a link to the fixed test project in the comments below.
It's failing because you're not satisfying the parameter types of any of ContentsOfDictionary's signatures.
entry.Value is of type Auto, so before calling ContentsOfDictionary you need to copy entry.Value into a Dictionary and pass that in to the function instead.
For example...
...
case "Dictionary"
dim d as new Xojo.Core.Dictionary = entry.Value
t = t + kEOL + ContentsOfDictionary( d, level + 1 )
end select

vbscript using InStr to find info that varies within a URL

I have a project where the user pulls up a specific URL where the values for Dept, Queue, and Day change by what hyperlink they choose. For example, they would click on a hyperlink and the URL would be something like:
http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptOne&Queue=18&Day=0
The next hyperlink could be:
http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptFive&Queue=13&Day=9.
I would like to use InStr to find Dept, Queue, and Day within the URL, then set their values to variables, such as UDept, UQueue, and UDay. Depending upon these values, the user can then copy a specific ID number that can only be found on the URL with these values. The end result would be a search for the URL:
http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=UDept&Queue=UQueue&Day=UDay
Here's my code so far:
Option Explicit
Dim objIE, objShell, objShellWindows
Dim strIDNum, strURL, strWindow, strURLFound, WShell, i
strURL = "http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptOne&Queue=18&Day=0"
strWindow = "Workflow Process"
Set objIE = CreateObject("InternetExplorer.Application")
Set objShell = CreateObject("Shell.Application")
Set objShellWindows = objShell.Windows
Set WShell = CreateObject("WScript.Shell")
strURLFound = False
'To fix item not found error
For Each objIE in objShellWindows
Next
For i = 0 to objShellWindows.Count - 1
Set objIE = objShellWindows.Item(i)
On Error Resume Next
If InStr(Ucase(objShellWindows.Item(i).LocationURL), Ucase(strURL)) Then
If InStr(Ucase(objShellWindows.Item(i).FullName), "IEXPLORE.EXE") Then
If Err.Number = 0 Then
If InStr(objShellWindows.Item(i).document.title, (strWindow)) Then
strURLFound = True
Exit For
End If
End If
End If
End If
Next
WShell.AppActivate strWindow
WScript.Sleep 300
strIDNum = objIE.document.getElementByID("ID_PlaceHolder").value
Thank you in advance to anyone who can help me with this.
Have you considered using a regular expression?
dim re, s
dim matches
s = "http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptFive&Queue=13&Day=9"
Set re = new RegExp
re.Pattern = ".*?Dept=(\w+)&Queue=(\d+)&Day=(\d+)$"
Set matches = re.Execute(s)
Dim uDept, uQueue, uDay
uDept = matches(0).submatches(0)
uQueue = matches(0).submatches(1)
uDay = matches(0).submatches(2)
Msgbox join(array("uDept = " & uDept, "uQueue = " & uQueue , "uDay = " & uDay), vbNewLine)
' Output:
' uDept = DeptFive
' uQueue = 13
' uDay = 9
To replace you can also use a Regular Expression:
Set re = new RegExp
s = "http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptFive&Queue=13&Day=9"
newDept = "DeptFourtyTwo"
newQueue = 404
newDay = 12
re.Pattern = "(Dept=)\w+"
newUrl = re.Replace(s, "$1" & newDept)
re.Pattern = "(Queue=)\d+"
newUrl = re.Replace(newUrl, "$1" & newQueue)
re.Pattern = "(Day=)\d+"
newUrl = re.Replace(newUrl, "$1" & newDay)
msgbox newUrl
' output:
' http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptFourtyTwo&Queue=404&Day=12
' Alternatively you can replace everything at once if the order and presence of
' parameters is guaranteed:
re.Pattern = "(Dept=)\w+(&Queue=)\d+(&Day=)\d+"
MsgBox re.Replace(s, "$1DeptFourtyTwo$2404$312")
This only using Instr and Mid Function's
s="http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptFive&Queue=13&Day=9"
a = InStr(s, "?") 'We get the value until ?
d1 = Mid(s, a)
c1 = InStr(d1, "=")
c2 = InStr(d1, "&")
d2 = Mid(d1, c2 + 1)
d3 = Mid(d1, c1 + 1, (c2 - c1) - 1) 'value of Dept is d3
c3 = InStr(d2, "=")
c4 = InStr(d2, "&")
d5 = Mid(d2, c4 + 1)
d4 = Mid(d2, c3 + 1, (c4 - c3) - 1) 'value of Queue is d4
c6 = InStr(d5, "=")
d6 = Mid(d5, c6 + 1) ' Value of Day is d6
Hope this helps

Does VBA have any built in URL decoding?

I just need to decode a URL, for example, replace %2E with .
I can hack out a method if one isn't build in, but my assumption is that there must be a URL decoding tool already existing.
Here's a snippet I wrote years ago
-markus
Public Function URLDecode(sEncodedURL As String) As String
On Error GoTo Catch
Dim iLoop As Integer
Dim sRtn As String
Dim sTmp As String
If Len(sEncodedURL) > 0 Then
' Loop through each char
For iLoop = 1 To Len(sEncodedURL)
sTmp = Mid(sEncodedURL, iLoop, 1)
sTmp = Replace(sTmp, "+", " ")
' If char is % then get next two chars
' and convert from HEX to decimal
If sTmp = "%" and LEN(sEncodedURL) + 1 > iLoop + 2 Then
sTmp = Mid(sEncodedURL, iLoop + 1, 2)
sTmp = Chr(CDec("&H" & sTmp))
' Increment loop by 2
iLoop = iLoop + 2
End If
sRtn = sRtn & sTmp
Next
URLDecode = sRtn
End If
Finally:
Exit Function
Catch:
URLDecode = ""
Resume Finally
End Function
No.
But here's one: URL Encoder and Decoder for VB
Or something along the lines of (possibly not complete):
Public Function URLDecode(ByVal strEncodedURL As String) As String
Dim str As String
str = strEncodedURL
If Len(str) > 0 Then
str = Replace(str, "&amp", " & ")
str = Replace(str, "&#03", Chr(39))
str = Replace(str, "&quo", Chr(34))
str = Replace(str, "+", " ")
str = Replace(str, "%2A", "*")
str = Replace(str, "%40", "#")
str = Replace(str, "%2D", "-")
str = Replace(str, "%5F", "_")
str = Replace(str, "%2B", "+")
str = Replace(str, "%2E", ".")
str = Replace(str, "%2F", "/")
URLDecode = str
End If
End Function
Also, take a look at How can I URL encode a string in Excel VBA?
EncodeURL and DecodeURL function using htmlfile object(Late binding)
I got this source from this site: http://cocosoft.kr/442
Function ENCODEURL(varText As Variant, Optional blnEncode = True)
Static objHtmlfile As Object
If objHtmlfile Is Nothing Then
Set objHtmlfile = CreateObject("htmlfile")
With objHtmlfile.parentWindow
.execScript "function encode(s) {return encodeURIComponent(s)}", "jscript"
End With
End If
If blnEncode Then
ENCODEURL = objHtmlfile.parentWindow.encode(varText)
End If
End Function
Function DECODEURL(varText As Variant, Optional blnEncode = True)
Static objHtmlfile As Object
If objHtmlfile Is Nothing Then
Set objHtmlfile = CreateObject("htmlfile")
With objHtmlfile.parentWindow
.execScript "function decode(s) {return decodeURIComponent(s)}", "jscript"
End With
End If
If blnEncode Then
DECODEURL = objHtmlfile.parentWindow.decode(varText)
End If
End Function
For example,
str = ENCODEURL("/?&=") 'returns "%2F%3F%26%3D"
str = DECODEURL("%2F%3F%26%3D") 'returns "/?&="
Here is the code from the URL posted in another answer in case it goes down as it works great.
http://www.freevbcode.com/ShowCode.asp?ID=1512
Public Function URLEncode(StringToEncode As String, Optional _
UsePlusRatherThanHexForSpace As Boolean = False) As String
Dim TempAns As String
Dim CurChr As Integer
CurChr = 1
Do Until CurChr - 1 = Len(StringToEncode)
Select Case Asc(Mid(StringToEncode, CurChr, 1))
Case 48 To 57, 65 To 90, 97 To 122
TempAns = TempAns & Mid(StringToEncode, CurChr, 1)
Case 32
If UsePlusRatherThanHexForSpace = True Then
TempAns = TempAns & "+"
Else
TempAns = TempAns & "%" & Hex(32)
End If
Case Else
TempAns = TempAns & "%" & _
Format(Hex(Asc(Mid(StringToEncode, _
CurChr, 1))), "00")
End Select
CurChr = CurChr + 1
Loop
URLEncode = TempAns
End Function
Public Function URLDecode(StringToDecode As String) As String
Dim TempAns As String
Dim CurChr As Integer
CurChr = 1
Do Until CurChr - 1 = Len(StringToDecode)
Select Case Mid(StringToDecode, CurChr, 1)
Case "+"
TempAns = TempAns & " "
Case "%"
TempAns = TempAns & Chr(Val("&h" & _
Mid(StringToDecode, CurChr + 1, 2)))
CurChr = CurChr + 2
Case Else
TempAns = TempAns & Mid(StringToDecode, CurChr, 1)
End Select
CurChr = CurChr + 1
Loop
URLDecode = TempAns
End Function
' URLDecode function in Perl for reference
' both VB and Perl versions must return same
'
' sub urldecode{
' local($val)=#_;
' $val=~s/\+/ /g;
' $val=~s/%([0-9A-H]{2})/pack('C',hex($1))/ge;
' return $val;
' }

Resources