Call Function when User Types Certain Keyword - vb.net

Okay, so I am working on a small scripting language using a VB Console Application.
I want the user to input "say('something')" and it calls the function I made named "say", is there a way to call the function and still use the following code:
Module Module1
Sub say(sayline)
Console.WriteLine(sayline)
End Sub
Sub Main()
Dim cmd As String
Console.WriteLine(">")
Do
Console.Write("")
cmd = Console.ReadLine()
If cmd IsNot Nothing Then cmd
Loop While cmd IsNot Nothing
End Sub
End Module

No, you cannot just call a method from user's string. You need to interpret the entered data.
First, you need to split your method name and arguments so that entered "say('something')" will transform to say and something. Remember that user can enter wrong data and you need to check if this call is correct - it's all about syntactic and lexical analysis. I hope you understand how to do this because it is pretty difficult.
Then, you need to check if you have a method called say. In case of plain and simple structure, switch construction will be enough. If your have such method, then pass something argument to this method. Else, output something like "unknown method".

If you wanted to call the method say upon typing the word say(something) and display the word something, then you can just have a certain condition that if the user types the word say within the input then call say method else, do whatever you want to do under else portion. Parse the input and omit the word say from the input and display it then.
You can have your code this way for example. (I just copied your code and added some codes to meet what you wanted... in my understanding)
Module Module1
Sub say(ByVal sayline)
Console.WriteLine(sayline)
End Sub
Sub Main()
Dim cmd As String
Do
Console.Write("> ")
cmd = Console.ReadLine()
Try
If cmd IsNot Nothing And cmd.Substring(0, 3).ToUpper().Equals("SAY") Then
say(parseInput(cmd))
End If
Catch ex As Exception
Console.WriteLine("message here")
End Try
Loop While cmd IsNot Nothing
End Sub
Function parseInput(ByVal cmd As String) As String
Dim input As String = ""
For index As Integer = 3 To cmd.Length - 1
If Char.IsLetter(cmd) Then
input += cmd.Substring(index, 1)
Else
input = input
End If
Next
Return input
End Function
End Module

Related

vb.net How to declare thread and call functions with it

I'm trying to use a thread to translate every text found in the Windows Forms to make my system multi-language.
I have a separate class named 'Language' with a sub and a function, sub reads a language source file, and function translates by receiving and returning a string.
Then I have my first Windows Form where I declare my thread:
Dim ThreadTraductor As New Thread(AddressOf ...) 'don't know how to do it
Dim cultureInfo As New System.Globalization.CultureInfo(ConfigurationManager.AppSettings('en').ToString)
ThreadTraductor.CurrentCulture = cultureInfo
ThreadTraductor.CurrentUICulture = cultureInfo
Basically I'm creating this thread to have a background process translating every Windows Form that's opened during execution, problem is I don't know how to declare it properly since I don't want to include any parameter when declaring, but I want the thread to be called from different Forms with parameters to translate, and also I want the thread to use my translate method inside Language class, is that possible? How?
Please assist, I haven't use threads before.
Public Class Lenguaje 'Class used to read language source file and translate strings
Public dicIdioma As New Dictionary(Of String, String)
Public Sub LeerArchivo(ByVal Culture As String)
Dim vectorAux() As String
dicIdioma.Clear()
Try
Dim LectorArchivo As New StreamReader("C:\Users\Joaqo\Desktop\Dorian VB\DorianBdBv1.0\UI\bin\Debug\" + Culture + ".txt")
Dim line As String
While Not LectorArchivo.Peek = -1
line = LectorArchivo.ReadLine()
vectorAux = line.Split(":")
dicIdioma.Add(vectorAux(0), vectorAux(1))
End While
Catch ex As System.IO.FileNotFoundException
MessageBox.Show("No se encuentra el archivo de idioma.")
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Public Function Traducir(ByRef frase As String) As String
Dim StringAux As String
For Each Item As String In dicIdioma.Keys
If Item = Char.ToLower(frase(0)) & frase.Substring(1) Then
StringAux = Char.ToUpper(dicIdioma.Item(Item)(0)) & dicIdioma.Item(Item).Substring(1)
frase = StringAux.Replace("_", " ")
ElseIf Item.Replace("_", " ") = Char.ToLower(frase(0)) & frase.Substring(1) Then
StringAux = Char.ToUpper(dicIdioma.Item(Item)(0)) & dicIdioma.Item(Item).Substring(1)
frase = StringAux.Replace("_", " ")
End If
Next
Return frase
End Function
End Class
Then I iterate every text object in my Windows Forms to translate them:
For Each Item As Label In Me.Controls.OfType(Of Label)()
Item.Text = Traductor.Traducir(Item.Text)
Next
For Each Item As Button In Me.Controls.OfType(Of Button)()
Item.Text = Traductor.Traducir(Item.Text)
Next
And it works just fine, but I'd be calling Traductor, Lenguaje's instance declared on my first interface, from the whole app, isn't that wrong somehow?
I was told that I should use Culture and CultureUI for this, but I'm not familiarized with that. What do you think? Sorry if I'm missing something, it's my first question here.

How do I select specific variables based on checkbox state as I iterate through a For Each

I'm working on a project that requires I iterate through a list of controls on a tabpage to find all of the checkboxes. Then depending on the state of the box (checked or unchecked) select individual variables (filenames) to then perform either a batch rename or delete of files on the filesystem (cb.checked = perform action).
I have managed to create the "for each" for the iteration of the controls (thanks google) but I'm struggling to figure out how to pick the variables. They are all named differently, obviously, as are the checkboxes. Also the checkboxes are statically assigned to the form/tabpage. Here's what I have at the moment.
Public Sub delBut_code(ByRef fname As String)
If (Sanity = 1) Then
For Each cb As Control In Form1.Controls
If TypeOf cb Is CheckBox AndAlso DirectCast(cb,
CheckBox).Checked Then
If My.Computer.FileSystem.FileExists(fname) Then
My.Computer.FileSystem.DeleteFile(fname)
End If
End If
Next
MessageBox.Show("All Actions Completed Successfully")
Else
MessageBox.Show("Please select a File To Delete")
End If
End Sub
and here is an example of some of the variables:
Dim castle As String = selPath & "\zm_castle_loadingmovie.txt"
Dim factory As String = selPath &
"\zm_factory_load_factoryloadingmovie.txt"
Dim island As String = selPath & "\zm_island_loadingmovie.txt"
N.B selpath collects a user entered folder path and can be ignored here
I would really appreciate any pointers.
First, you can do much better with the loop:
Public Sub delBut_code(ByRef fname As String)
If Sanity <> 1 Then
MessageBox.Show("Please select a File To Delete")
Exit Sub
End If
Dim checked = Form1.Controls.OfType(Of CheckBox)().Where(Function(c) c.Checked)
For Each box As CheckBox in checked
Try
'A file not existing is only one reason among many this could fail,
' so it needs to be in a Try/Catch block.
' And once you're using a Try/Catch block anyway,
' the FileExists() check becomes a slow and unnecessary extra trip to the disk.
My.Computer.FileSystem.DeleteFile(fname)
Catch
'Do something here to let the user know it failed for this file
End Try
Next
MessageBox.Show("All Actions Completed")
End Sub
But now you need to know how have the right value in that fname variable. There's not enough information in the question for us to fully answer this, but we can give some suggestions. There a number of ways you could do this:
Set the Tag property in the Checkboxes when you build the string variables. Then fname becomes DirectCast(box.Tag, String).
Inherit a custom control from CheckBox to use instead of a normal Checkbox that has an additional String property for the file name. Set this property when you build the string variables.
Name your string variables in a way that you can derive the string variable name from the CheckBox variable name, and then use a Switch to pick the right string variable from each box.Name.
Keep a Dictionary(Of CheckBox, String) that maps the Checkboxes to the right string values.
But without knowing more context of the application, I hesitate to recommend any of these over the others as best for your situation.

RunCode does not Run a Public Function in MS Access

I am new to MS Access and I am trying to create a simple Macro with a call to VBA code.
the VBA code here is a sample (which also doesn't run)
Public Function RunImport()
Dim N As Integer
Dim Message1, Message2, Title, Default1, Default2, JulianSD, JulianED
Message1 = "Enter Julian Start Date"
Message2 = "Enter Julian End Date"
Title = "User Input Section"
Default1 = "17365"
Default2 = "17000"
JulianSD = InputBox(Message1, Title, Default1)
JulianED = InputBox(Message2, Title, Default2)
End Function
do you think you might be able to locate an issue here?
Thanks!
PS. I am using Version 14.0.7177.500 (32-bit). it wasn't my choice.. (if it were, I wouldn't be using access.. :p)
The most common use of a function is to return a value or values. Your function does not appear to be returning any value. At the end of a function you would normally have a line of code that says what value the function will return, for example....
RunImport = JulianSD - JulianED
End Function
A line like this would usually be inserted before the 'End Function' line. However if your intention is not to return a value, but instead you just want to run a vba macro, perhaps you need to change your function to a Sub routine...
Public Sub RunImport()
'code goes here
End Sub

"Object reference not set to an instance of an object" message

I keep getting window that pops up when I run a VB.NET console program I made that simply says "Object reference not set to an instance of an object." The window doesn't even say "error" or anything--the title is simply the name of the project. However...I'm assuming this is something I don't want.
I searched around a bit and found posts about similar messages but couldn't figure out how they applied to my situation.
Here is some of my code. (This program is supposed to take some data from a preformatted text file that describes the geometry of a cross section of a river and systematically enters some new geometric data to represent the riverbed being cleaned/cleared out in a certain way, and then write the new data to a new file in a similar format.)
Imports System
Imports System.IO
Imports Microsoft.VisualBasic.FileIO
Module module1
Public Sub Main()
Using sr As New StreamReader("C:\inputfile.txt")
Using outfile As New StreamWriter("C:\outputfile.txt")
Dim line As String = ""
Dim styles As Globalization.NumberStyles
styles = Globalization.NumberStyles.AllowLeadingSign Or Globalization.NumberStyles.AllowDecimalPoint
Dim stations(-1) As Double
Dim elevations(-1) As Double
Dim i As Integer = 0
Do
Try
line = sr.ReadLine()
Dim stringarray() As String = line.Split()
ReDim Preserve stations(i)
ReDim Preserve elevations(i)
stations(i) = Double.Parse(stringarray(0), styles)
elevations(i) = Double.Parse(stringarray(1), styles)
Catch ex As Exception
MsgBox(ex.Message)
End Try
i = i + 1
Loop Until line Is Nothing
Dim min As Double = elevations(0)
(some more code.....)
End Using
End Using
End Sub
End Module
I only included the first part of my code because when I put a break at the "Loop Until line Is Nothing" statement, the message didn't come up until after I went through the break, but when I put the break at the "Dim min As Double = elevations(0)" statement, the message came up before the program got to the break.
I don't really get what's wrong with my code. Anyone have any ideas?
Thanks!
See if this works any better:
Public Sub Main()
Dim styles As Globalization.NumberStyles = Globalization.NumberStyles.AllowLeadingSign Or Globalization.NumberStyles.AllowDecimalPoint
Dim stations As New List(Of Double)
Dim elevations As New List(Of Double)
For Each line As String in File.ReadLines("C:\inputfile.txt")
Try
Dim stringarray() As String = line.Split()
stations.Add(Double.Parse(stringarray(0), styles))
elevations.Add(Double.Parse(stringarray(1), styles))
Catch ex As Exception
MsgBox(ex.Message)
End Try
Next Line
Dim min As Double = elevations(0)
Using outfile As New StreamWriter("C:\outputfile.txt")
End Using
End Sub
Note that I moved your output file to the end... you haven't written anything yet, and so it's a good idea to wait as long as possible to open it, to keep it open for as short a time as possible.
The code fails after the last line has been read because the exit condition (Loop Until) doesn't know that you have reached the end of file. So another loop is started and the code tries to read an inexistent line. The last ReadLine returns Nothing, but the code tries to split it.
You could add a check before trying to split the line and jump directly to the Loop Until statement if you don't have anymore lines to read. Of course I also suggest to remove the array redim at every loop and use a more flexible List(Of Double)
Dim stations = New List(Of Double)
Dim elevations = New List(Of Double)
Do
Try
' After the last line this command returns null (Nothing in VB)
line = sr.ReadLine()
if line IsNot Nothing Then
Dim stringarray() As String = line.Split()
stations.Add(Double.Parse(stringarray(0), styles))
elevations.Add(Double.Parse(stringarray(1), styles))
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
Loop Until line Is Nothing
OK...I feel really dumb now...after reading through all of your answers and looking at Steve's code, I realized my code was going through the loop one last time where "line" was set as nothing at the beginning of the loop and it was still trying to add "nothing" as an element to the arrays. The key to fixing it was adding an "If line IsNot Nothing" statement before the statements adding elements to the arrays, which Steve had.
Thank you all for your answers!

calling a function from a form into a module

I have a an array in my module, so I want to display the contents of my array in a form textbox, here is my array
Module Module1
Sub AddCourse()
Dim Subjects() = {"Ms Office 2007", "internet and commmunications", "Lifetime skills"}
For i = 0 To UBound(Subjects) ' FOR LOOP TO WRITE AN ARRAY
i = i +1
Subjects(i)
Next
txtComputer.Text = subjects()
my problem is, when I try to use my texbox txtComputer in my module I get an error.
My question is, how do I make a form textbox to be used in a module
I get an error that reads "Error'txtComputer' is not declared. It may be inaccessible due to its protection level."
My question is based on, how do I get this error fixed?
There are several suggestions I have for you.
First, don't use UBound. That's an old VB6 function that is only provided for backwards compatability. You should instead use Subjects.Length.
Next, when you're incrementing the i variable, you don't need to say i = i + 1. You can just use the += operator for that (e.g. i += 1).
However, you shouldn't be explicitly incrementing i inside your For loop, anyway. The loop automatically increments the variable for you each time it iterates through the loop. If you do it explicitly yourself inside the loop, like that, it will skip every other item.
Next, in this case, you really should just use a For Each loop, rather than an iterator:
For Each subject As String in Subjects
'...
Next
Next, you aren't actually concatenating the items together inside you loop. You should be doing something like this:
For Each subject As String in Subjects
txtComputer.Text += subject
Next
However, in that case, for efficiency sake, you really ought to use a StringBuilder, like this:
Dim builder As New StringBuilder()
For Each subject As String in Subjects
builder.Append(subject)
Next
txtComputer.Text = builder.ToString()
But, all of this is moot because all you really need to do is to call String.Join:
txtComputer.Text = String.Join(", ", Subject)
As far as why you can't access the text box from the module, that is because the module is a separate object, so the text box is entirely out of scope. For instance, what if you had two instances of your form displayed at the same time? How in the world would this module know which form's text box you were referring to? The simplest way to correct that would be to pass a reference to your form into the module's method, like this:
Module Module1
Sub AddCourse(f As MyFormName)
f.txtComputer.Text = "Hello world"
End Sub
End Module
And then you could call it from the form, like this:
AddCourse(Me)
However, that would be exceptionally bad practice. Ideally, nothing outside of the form's code should ever deal directly with any of the controls on the form. So, the far better way to do it would be to simply have the method return the data, and then have the form set it's own control to the data that is returned, for instance:
Module Module1
Function GetCourse() As String
Return "Hello world"
End Function
End Module
And then call it from the form like this:
txtComputer.Text = GetCourse()
You can use String.Join to create a string which separates each subject with Environment.NewLine:
txtComputer.Text = String.Join(Environment.NewLine, Subjects)
The problem with your for loop is that it makes no sense at all since you have already declared and initialized the array in one line.
If you want to use a loop anyway, you can use a StringBuilder to concat all strings together:
Dim subjectBuilder = New System.Text.StringBuilder
For Each subject In Subjects
subjectBuilder.Append(subject).Append(Environment.NewLine)
Next
If subjectBuilder.Length <> 0 Then subjectBuilder.Length -= Environment.NewLine.Length
txtComputer.Text = subjectBuilder.ToString()