Making a textbased game. I have a command prompt its made from richtextbox as outputbox and
textbox for inputtextbox. i need to make some commands like "cls" "dir" "config". lots of more commands in my list. i just stuck how to that and how to approach to solution.
Here is my code i tyred some of 'em with select case method but its too primitive.
Private Sub Output(s As String)
If s <> "" Then
nCounter = nCounter + 1
sCounter = Convert.ToString(nCounter)
consoleoutputbox.AppendText(vbCrLf & sCounter & " " & s)
End If
End Sub
Private Sub consoleinputbox_KeyDown(sender As Object, e As KeyEventArgs) Handles consoleinputbox.KeyDown
Dim Command As String = consoleinputbox.Text
If e.KeyCode = Keys.Enter Then
If Command <> "" Then
Select Case Command
Case "cls"
consoleoutputbox.Clear()
consoleinputbox.Clear()
consoleinputbox.Focus()
nCounter = 0
Case "help"
Output("Welcome to help section. Avaliable commands:")
Output("help, cls")
Case Else
Output(Command)
consoleinputbox.Clear()
consoleinputbox.Focus()
End Select
End If
End If
End Sub
Perhaps a Dictionary(Of String, Action) would help. Put each thing(s) you want done into sub routines and add them to the dictionary with the command as the key:
Dim Commands As New Dictionary(Of String, Action)
Commands.Add("test1", New Action(AddressOf test))
Then just pass the string to the dictionary as the index and invoke the sub routine
Commands("test1").Invoke()
One option might be to define a module and add methods named after your commands. You could then use Reflection to find and invoke the method with the name entered by the user as a command.
Related
i have an external class(colorCode.vb) in same project as my main form.vb.
My objective is to send a value as argument as i call a method in the colorCode.vb class, and use the value returned by the method. I don't know if its logically possible . Here i tried this but failed.
in my colorCode.vb Class i have this codes:
Public Sub getValue(ByVal itemCode As Integer)
Dim codeVal() As Integer = {9999, 3034, 3040, 3035}
Dim colorVal As String
For counter As Integer = 0 To codeVal.Count Step 1
If (itemCode = codeVal(counter)) Then
Select Case codeVal(counter)
Case 9999
colorVal = "BRILLIANT WHITE EMULSION"
Case 3034
colorVal = "OFF-WHITE EMULSION"
End Select
End If
Next
End Sub
and in my main form.vb i did this
Private Sub descTextBox_TextChanged(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles descTextBox.TextChanged
Dim colorDesc As colorCode = New colorCode()
Dim itemCode As Integer = Integer.Parse(itemCodeTextBox.Text)
descTextBox.Text = colorDesc.getValue(itemCode)'this line triggers an error.
End Sub
please i need some help here. already running nuts
Please turn on Option Strict. This is a 2 part process. First for the current project - In Solution Explorer double click My Project. Choose Compile on the left. In the Option Strict drop-down select ON. Second for future projects - Go to the Tools Menu -> Options -> Projects and Solutions -> VB Defaults. In the Option Strict drop-down select ON. This will save you from bugs at runtime.
Subs in vb.net do not return values. You need a Function. Instead of looping through the array you can just check if the array contains itemCode and if it does proceed with the Select Case.
Do not put your code in the text changed. It will run every time a character is entered before your user has a chance to enter the entire code. Create a button and use that. Use .TryParse to validate the input. It will return True if valid and fill in the second parameter with the number.
Public Class colorCode
Public Function getValue(ByVal itemCode As Integer) As String
Dim codeVal() As Integer = {9999, 3034, 3040, 3035}
Dim colorVal As String = ""
If codeVal.Contains(itemCode) Then
Select Case itemCode
Case 9999
colorVal = "BRILLIANT WHITE EMULSION"
Case 3034
colorVal = "OFF-WHITE EMULSION"
Case 3040
colorVal = "Blue"
Case 3035
colorVal = "Green"
End Select
Else
colorVal = "No matching color"
End If
Return colorVal
End Function
End Class
And in the form...
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim itemCode As Integer
If Integer.TryParse(TextBox1.Text, itemCode) Then
Dim colorDesc As colorCode = New colorCode()
TextBox2.Text = colorDesc.getValue(itemCode)
Else
MessageBox.Show("Please enter a valid number")
End If
End Sub
Add the return statement. You should also check the value of itemCodeTextBox.Text to make sure it's a numeric value before you call colorDesc.getValue otherwise your program may crash if a non-numeric value is entered into the textbox
You are missing the "return" part of your method.
Public Function getValue(ByVal itemCode As Integer) As String
That's what it'll take to declare you're returning a string value, and then you actually return your vale at the end of the method.
Next
return colorVal
End Sub
There are other ways to do this as well as better ways to deal with your "getValue" code, but this should get you running for now. The rest of the improvements are likely a different Question, or even series of Questions. Or you could go to the Code Review stack and get more help there.
So I'm reading through my source code looking for places to improve the code when I come across this unholy chunk of code.
Public Function ReadPDFFile(filePath As String,
Optional maxLength As Integer = 0) As List(Of String)
Dim sbContents As New Text.StringBuilder
Dim cArrayType As Type = GetType(PdfSharp.Pdf.Content.Objects.CArray)
Dim cCommentType As Type = GetType(PdfSharp.Pdf.Content.Objects.CComment)
Dim cIntegerType As Type = GetType(PdfSharp.Pdf.Content.Objects.CInteger)
Dim cNameType As Type = GetType(PdfSharp.Pdf.Content.Objects.CName)
Dim cNumberType As Type = GetType(PdfSharp.Pdf.Content.Objects.CNumber)
Dim cOperatorType As Type = GetType(PdfSharp.Pdf.Content.Objects.COperator)
Dim cRealType As Type = GetType(PdfSharp.Pdf.Content.Objects.CReal)
Dim cSequenceType As Type = GetType(PdfSharp.Pdf.Content.Objects.CSequence)
Dim cStringType As Type = GetType(PdfSharp.Pdf.Content.Objects.CString)
Dim opCodeNameType As Type = GetType(PdfSharp.Pdf.Content.Objects.OpCodeName)
Dim ReadObject As Action(Of PdfSharp.Pdf.Content.Objects.CObject) = Sub(obj As PdfSharp.Pdf.Content.Objects.CObject)
Dim objType As Type = obj.GetType
Select Case objType
Case cArrayType
Dim arrObj As PdfSharp.Pdf.Content.Objects.CArray = DirectCast(obj, PdfSharp.Pdf.Content.Objects.CArray)
For Each member As PdfSharp.Pdf.Content.Objects.CObject In arrObj
ReadObject(member)
Next
Case cOperatorType
Dim opObj As PdfSharp.Pdf.Content.Objects.COperator = DirectCast(obj, PdfSharp.Pdf.Content.Objects.COperator)
Select Case System.Enum.GetName(opCodeNameType, opObj.OpCode.OpCodeName)
Case "ET", "Tx"
sbContents.Append(vbNewLine)
Case "Tj", "TJ"
For Each operand As PdfSharp.Pdf.Content.Objects.CObject In opObj.Operands
ReadObject(operand)
Next
Case "QuoteSingle", "QuoteDbl"
sbContents.Append(vbNewLine)
For Each operand As PdfSharp.Pdf.Content.Objects.CObject In opObj.Operands
ReadObject(operand)
Next
Case Else
'Do Nothing
End Select
Case cSequenceType
Dim seqObj As PdfSharp.Pdf.Content.Objects.CSequence = DirectCast(obj, PdfSharp.Pdf.Content.Objects.CSequence)
For Each member As PdfSharp.Pdf.Content.Objects.CObject In seqObj
ReadObject(member)
Next
Case cStringType
sbContents.Append(DirectCast(obj, PdfSharp.Pdf.Content.Objects.CString).Value)
Case cCommentType, cIntegerType, cNameType, cNumberType, cRealType
'Do Nothing
Case Else
Throw New NotImplementedException(obj.GetType().AssemblyQualifiedName)
End Select
End Sub
Using pd As PdfSharp.Pdf.PdfDocument = PdfSharp.Pdf.IO.PdfReader.Open(filePath, PdfSharp.Pdf.IO.PdfDocumentOpenMode.ReadOnly)
For Each page As PdfSharp.Pdf.PdfPage In pd.Pages
ReadObject(PdfSharp.Pdf.Content.ContentReader.ReadContent(page))
If maxLength > 0 And sbContents.Length >= maxLength Then
If sbContents.Length > maxLength Then
sbContents.Remove(maxLength - 1, sbContents.Length - maxLength)
End If
Exit For
End If
sbContents.Append(vbNewLine)
Next
End Using
'Return sbContents.ToString
Dim ReturnList As New List(Of String)
For Each Line In sbContents.ToString.Split(vbNewLine)
If String.IsNullOrWhiteSpace(Line.Trim) Then
Else
ReturnList.Add(Line.Trim)
End If
Next
Return ReturnList
End Function
All this does is read the text parts of a PDF using PDFSharp. What caught my eye however was line 17. Is that a Sub inside of the function?
So, what exactly is this Sub inside of a function? I didn't write this code so I've never seen anything like this before.
How does this work exactly and why wouldn't I use a function to do the processing and then return the results?
In short, my question is, what is this, how does it work, and why would I want to use something like this?
That's a so-called Lambda expression. They're used to create inline (or more correctly: in-method) methods, which makes them more dynamic than normal methods.
In your example a lambda expression is not necessary and only makes the code harder to understand. I suppose the author of that code wrote a lambda expression instead of a separate method in order to not expose ReadObject to any outside code.
One of the best uses for a lambda expression IMO is when you want to make thread-safe calls to the UI thread, for instance:
If Me.InvokeRequired = True Then
Me.Invoke(Sub() TextBox1.Text = "Process complete!")
Else
TextBox1.Text = "Process complete!"
End If
...where the same code without a lambda would look like this:
Delegate Sub UpdateStatusTextDelegate(ByVal Text As String)
...somewhere else...
If Me.InvokeRequired = True Then
Me.Invoke(New UpdateStatusTextDelegate(AddressOf UpdateStatusText), "Process complete!")
Else
UpdateStatusText("Process complete!")
End If
...end of somewhere else...
Private Sub UpdateStatusText(ByVal Text As String)
TextBox1.Text = Text
End Sub
There are also other examples where lambda expressions are useful, for instance if you want to initialize a variable but do some processing at first:
Public Class Globals
Public Shared ReadOnly Value As Integer = _
Function()
DoSomething()
Dim i As Double = CalculateSomething(3)
Return Math.Floor(3.45 * i)
End Function.Invoke()
...
End Class
Yet another usage example is for creating partially dynamic event handlers, like this answer of mine.
Coming from Python, I cannot figure out a way to accomplish my end goal since a function like eval() does not exist with Excel VBA.
Below is what I am trying to achieve by using a simple example that I can scale:
Dim userinput as String
userinput = inputbox("A=John, B=Kate, C=Tim", "Enter a letter that corresponds with your name: ")
Dim A as String
Dim B as String
Dim C as String
A = John
B = Kate
C = Tim
Dim Phrase as Variant
phrase = msgbox("Hello, my name is " & userinput)
Result:
User enters a C
msg box pops up as "Hello, my name is Tim"
Regardless of what I try to do, I cannot have a userinput correspond to a variable that is then interpreted while in a string. My macro would be useless without a user's input referencing a much longer and complex phrase that would be too hard for a user to enter on their own.
You're presenting a finite, pre-determined set of options to the user.
Yet you let them enter quite literally anything, not validated, and roll with it.
A much better alternative would be to ditch the InputBox approach and present the user with an actual UserForm, so that the user's input is constrained to a finite, pre-determined set of options - a ComboBox control comes to mind:
The UserForm's code-behind is pretty straightforward - hide the form when a button is clicked, treat "X-out" as a cancellation, expose the user's Selection and whether the form was cancelled via Property Get members, and populate the dropdown with the possible values to pick from:
Option Explicit
Private isCancelled As Boolean
Public Property Get Cancelled() As Boolean
Cancelled = isCancelled
End Property
Public Property Get Selection() As String
Selection = ComboBox1.Value
End Property
Private Sub CancelButton_Click()
isCancelled = True
Hide
End Sub
Private Sub OkButton_Click()
Hide
End Sub
Private Sub UserForm_Activate()
With ComboBox1
.Clear
.AddItem "Lorem"
.AddItem "Ipsum"
'...
End With
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
Cancel = True
isCancelled = True
Hide
End If
End Sub
And now you can do this:
Public Sub Test()
With New UserForm1
.Show
If Not .Cancelled Then
MsgBox .Selection
End If
End With
End Sub
This handles the user cancelling out of the prompt, and if your ComboBox control's Style property is set to fmStyleDropDownList, there's absolutely no way the user can supply a value you're not expecting. And you can extend it further by supplying Property Get and Property Let members to configure the Title and Instructions labels as needed, or make the calling code responsible for supplying the list of valid values to populate the ComboBox with.
That's one part of the problem. The next part is "mapping" inputs with another string value. The best data structure for this is a Dictionary, but a keyed Collection can work just as well:
Dim values As Collection
Set values = New Collection
values.Add "string 1", "Lorem"
values.Add "string 2", "Ipsum"
'...
With New UserForm1
.Show
If Not .Cancelled Then
MsgBox values(.Selection)
End If
End With
Of course there are many ways to populate the data you need here, both for the combobox values and the mapped strings in the collection; you can hard-code them like this, or get them from a Range on a worksheet, or from a database, whatever rocks your boat.
The user is typing a letter. You need code to more explicitly translate that into a name. There are a lot of methods - if you have a long list or a user-entered list you may need a solution that is more dynamic. However here is a fix for your code:
Dim userinput as String
userinput = inputbox("A=John, B=Kate, C=Tim", "Enter a letter that corresponds with your name: ")
Dim A as String
Dim B as String
Dim C as String
Dim nameOut as String
select case userinput
case "A"
nameOut = "John"
case "B"
nameOut = "Kate"
case "C"
nameOut = "Tim"
end select
Dim Phrase as Variant
phrase = MsgBox("Hello, my name is " & nameOut)
Note: don't forget to enclose strings in double quotes.
Not to take away from Scott's answer but for a potentially more dynamic approach it seems class modules and callbyname have an answer:
Class module - class1
Private pa As String
Public Property Get a() As String
a = pa
End Property
Public Property Let a(value As String)
pa = value
End Property
Test sub
Sub testing()
Dim cls1 As Class1
Set cls1 = New Class1
cls1.a = "tim"
userinput = "a"
Debug.Print CallByName(cls1, userinput, VbGet)
End Sub
Posted just because it's a different approach. It finds the position of the inputted letter in an array of all three, and then finds the corresponding item in an array of the names.
Sub x()
Dim userinput As String
Dim Phrase As String
Dim v
userinput = InputBox("A=John, B=Kate, C=Tim", "Enter a letter that corresponds with your name: ")
v = Array("John", "Kate", "Tim")
With Application
If IsNumeric(.Match(userinput, Array("A", "B", "C"), 0)) Then
Phrase = .Index(v, .Match(userinput, Array("A", "B", "C"), 0))
MsgBox "Hello, my name is " & Phrase
Else
MsgBox "Wrong letter"
End If
End With
End Sub
There's lots and lots of pages on the internet regarding threading but I can't seem to get my head around it.
I have a Form, which on the click of a button, loops through a file and reads it line by line. Each line is the login details for different FTP sites.
When it reads a line, it Dim's a variable as a new instance of a class named CallFTP using the login details.
It then Dim's a variable as a new Thread using a function in CallFTP named PerformFTP.
PerformFTP returns a string with the results of the FTP and I want to add this to a ListBox on the form that began it all.
The code for the button goes like this...
Private Sub cmdRun_Click(sender As Object, e As EventArgs) Handles cmdRun.Click
For Each _FTPLine As String In Split(_FTPDetails, vbNewLine)
Dim _Active As Boolean = CBool(Split(_FTPLine, "|")(7))
If _Active Then
_CurNum += 1
_ID = Format(Now.Year, "0000") & Format(Now.Month, "00") & Format(Now.Day, "00") & Format(Now.Hour, "00") & Format(Now.Minute, "00") & Format(Now.Second, "00") & Format(Now.Millisecond, "000") & Format(_CurNum, "00000")
Dim _FTP As New CallFTP(_ID, Split(_FTPLine, "|")(0), Split(_FTPLine, "|")(1), Split(_FTPLine, "|")(2), Split(_FTPLine, "|")(3), Split(_FTPLine, "|")(4), Split(_FTPLine, "|")(5), Split(_FTPLine, "|")(6))
Dim _Thread = New Thread(New ThreadStart(AddressOf _FTP.PerformFTP))
With _Thread
.IsBackground = True
.Start()
End With
End If
Next _FTPLine
End Sub
The class is as below (not quite but you don't need the rest of the code lol)
Public Class CallFTP
Private _ID As String = ""
Private _Response As String = ""
Private _IPAddress As String = ""
Private _Port As String = ""
Private _User As String = ""
Private _Pass As String = ""
Private _Remote As String = ""
Private _Local As String = ""
Private _InOut As String = ""
Public Sub New(ID As String, Server As String, PortNum As String, Username As String, Password As String, RemoteDir As String, LocalDir As String, InOrOut As String)
_ID = ID
_IPAddress = Server
_Port = PortNum
_User = Username
_Pass = Password
_Remote = RemoteDir
_Local = LocalDir
_InOut = InOrOut
End Sub
Public Function PerformFTP() As String
Return "This is a test"
End Function
End Class
Could anyone explain how I would call a sub named LogMessage on a module named modMisc (which adds a string to a ListBox on the main form)?
I've read that you need to invoke it but everything I read seems to give me a headache and make me need to lie down in a dark room for a few hours.
Is anyone capable of explaining as though you're speaking to a 2 year old? :)
Any help would be much appreciated.
You need to invoke a delegate to update your GUI if you're going to update it from another thread that from where it was created.
1º Your delegate must match (have the same signature) than the method you'll use:
Delegate Sub LogMessageExampleDelegate(ByVal x As Integer, ...)
Signature means that the delegate must return and receive the same types than your function/method.
2º Call your function to update GUI using delegate. This for example inside your update GUI function:
If yourListBox.InvokeRequired Then
yourListBox.Invoke(New LogMessageExampleDelegate(AddressOf THE_FUNCTION_WHICH_UPDATES_THE_GUI_NAME), parameter_value)
Else
'Just call your function
End If
With, as example:
sub addToListBox(byval text as string)
myListBox.Items.add(text)
end sub
So your invoke would be:
If yourListBox.InvokeRequired Then
yourListBox.Invoke(New LogMessageExampleDelegate(AddressOf addToListBox), "Item 1")
Else
'Just call your function
addToListBox("Item 1")
End If
PS: I wrote it two times so hope I didn't mess up with something without noticing it.
I'm starting with Visual Basic and use Visual Studio 2012 and trying to make a tool for renaming a group of files.
How it shoul be:
1- With the "Select Files" button, I can choose the files and they are listed in the ListBox
2- "Old value" is a textbox and is the value to be changed in the filename. For example: fff
3- "New value" is a textbox and is the new value that should replace the old. For example: zzz
4- Rename is a button to start the process.
To rename only one file it's not a problem.
But how to rename all the files from the ListBox which are containing the Oldvalue ?
Can you please help me!
Thanks
I suggest looping over the selected files in the listbox, checking to see which ones contain the OldValue string.
You could use string.contains http://msdn.microsoft.com/en-us/library/dy85x1sa(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1
Sounds like you have the replace function sorted since you say it's no problem to do just one file.
Thank you 70Mike.
But I have some problem with the loop.
If it works only for 1 file and not for all.
Here is my code:
Public Class frmRename
Private Sub cmdSelectFile_Click(sender As Object, e As EventArgs) Handles cmdSelectFile.Click
If (OpenFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK) Then
For Each S As String In OpenFileDialog1.FileNames
lstSelectFiles.Items.Add(S)
Next
Else : Exit Sub
End If
End Sub
Private Sub cmdRename_Click(sender As Object, e As EventArgs) Handles cmdRename.Click
Try
For LC As Integer = 0 To lstSelectFiles.Items.Count - 1
Dim s1 As String = lstSelectFiles.Items(LC)
Dim s2 As String = txtbOld.Text
Dim b As String
b = s1.Contains(s2)
Console.WriteLine("Is the string, s2, in the string, s1?: {0}", b)
Do While b = True
Dim oldFile As String = lstSelectFiles.Items(LC)
Dim newFile As String = Replace(lstSelectFiles.Items(LC), txtbOld.Text, txtbNew.Text)
If File.Exists(oldFile) And Not File.Exists(newFile) Then
File.Move(oldFile, newFile)
Kill(oldFile)
End If
Loop
Next
Catch ex As Exception
MsgBox("No file renamed")
End Try
End Sub
End Class