Key input functions for a VB class file - vb.net

I am working on a little framework and I want to have a class file that contains functions I can run to check if a certain key has been pressed so other events can be run. The only code I have found online for similar things are written into the form itself and use something like "Handles Me.KeyPress". However, this handle function can't be used in a class file.
Public Function OnKeyPress(KeyToCheck As Keys)
If KeyPressed = KeyToCheck then
return true
else
return false
End If
End Function
I have tried:
Public Function OnKeyPress(KeyToCheck As Keys)Handles Formname.Keypress
If KeyPressed = KeyToCheck then
return true
else
return false
End If
End Function
However, this does not work. Any suggestions or work arounds would be greatly appreciated.

To get keyboard input, you need to have a window. All input goes to a window, and that window can then check for key presses that are sent to it.
To get global information, you'd need to install a hook, but those should generally be avoided.

Related

How to open a form within non-GUI code in VB.NET

I write a program in Visual Basic, which doesn't need - and doesn't have - a GUI unless a certain event happens, in which the user needs to be involved (and a MsgBox wouldn't suffice).
Now I want to call a form (which I have already created in the project) from my code. So I want to call
Public Class MyForm
{...} 'In my case empty
End Class
from within
Module MyMain
{...} 'do unrelated stuff
'Call MyForm somehow
{...} 'proceed stuff, knowing users input
End Module
I see the form for a very brief moment, but I can't get my program to halt and wait for me, while I am in the form.
The code in my desperation is:
Module MyMain
{...} 'do unrelated stuff
Dim wifo As New MyForm()
wifo.Show()
wifo.Visible = True
wifo.Activate()
wifo.Focus()
{...} 'proceed stuff, knowing users input
End Module
How does one do it?
If I understand you correctly, you want the Form.ShowDialog() method...
https://msdn.microsoft.com/en-us/library/c7ykbedk(v=vs.110).aspx

Can I dynamically call a local function?

I have a module that looks like this. I've simplified it greatly so as not to clutter up my question (my local functions are more complex than this). Here is my code:
decision = {}
function win(win_arg) return win_arg end
function lose(lose_arg) return lose_arg end
local function draw(draw_arg) return draw_arg end
function decision.get_decision(func, arg)
return func(arg)
end
return decision
I am calling my module with the code below.
my = require "my-lua-script"
print(my.get_decision(lose, "I lose."))
print(my.get_decision(win, "I win."))
I want 'get_decision' to be a public method. I want win, lose and draw to be private, but I want to call them dynamically from get_decision. If I understand correctly, win and lose are in the global namespace right now? If I put a local in front of these two methods (like draw) then my code doesn't work.
Is there a way to accomplish what I am after?
Of course.
my-script.lua
-- This is the local side of the module.
local outcomes = {}
function outcomes.win(arg) return arg end
function outcomes.lose(arg) return arg end
function outcomes.draw(arg) return arg end
-- This is the exposed side of the module.
local M = {}
function M.get_decision(outcome, arg)
return outcomes[outcome](arg)
end
return M
main.lua
local my = require'my-script'
print(my.get_decision('win', 'I win.'))
print(my.get_decision('lose', 'I lose.'))
You simply use a string to indicate which function you'd like to access, and use that string to index a table of functions from within get_decision against outcomes. This will keep the functions hidden behind get_decision.

Threading in VB.net

I have a very basic doubt in vb.net threading.
I am having a function MyFunc1() which actually launches a form and asks for input from the user and returns a string. The return must be done only when user clicks a button called 'return' in the Form.
So I framed the function like this.
Public done as Boolean = true
Public str as String
Function MyFunc1() As String
Start Thread1 //launch UI as seperate thread
While done
End While //Infinite loop to hold the parent loop till done is made as false
return str
End Function
Function Thread1
//code to launch UI
End Function
Function onClickReturn //Function triggered when 'return' is pressed
str = EditText.text
done = false
End Function
The problem right now is Thread1 launches the UI but once the UI is launched Thread1 dies and so does the UI Panel.
Any ways to fix this?
I think what you are trying to do doesn't event need threads. Since your blocking the original thread anyways, there is really no need to create a second thread. Typically you just call
MyForm.ShowDialog()
That shows a modal dialog and will block the calling code at that line, allowing the UI to be displayed and used until the user dismisses it.
If you have a .Net thread object, you can block by calling Thread.Join.

Default property set being called mysteriously called in VB.NET

Here is my scenario.
I have the following line of code in my program:
JCL_History.Enqueue(JCL_History(I))
This JCL_History object is basically a Generic.List encapsulated in a wrapper and has the following method:
Public Sub Enqueue(ByRef value As String)
If Members.Contains(value) Then
Me.RemoveAt(Members.IndexOf(value))
ElseIf _Count = _MaxCount Then
Me.RemoveAt(_Count - 1)
End If
Me.Insert(0, value)
End Sub
So you see that the first line of code that invokes Enqueue should "shuffle" items around.
Also, the wrapper class of which JCL_History is a type has the following default property:
Default Public Property Item(ByVal Index As Integer) As String 'Implements Generic.IList(Of String).Item
Get
If Index < _MaxCount Then
Return Members(Index)
Else
Throw New IndexOutOfRangeException("Bug encountered while accessing job command file history, please send an error report.")
End If
End Get
Set(ByVal value As String)
If Index < _MaxCount Then
If Index = _Count Then _Count = _Count + 1
Members(Index) = value
Else
Throw New IndexOutOfRangeException("Bug encountered while accessing job command file history, please send an error report.")
End If
End Set
End Property
In my testing I have 2 items in this JCL_History list. When I call that first line of code I posted (the one that invokes Enqueue) with I = 1 I expect the first item to be shuffled to the bottom and the second item to be shuffled to the top.
After the thread returns from Enqueue I notice that this is exactly what happens to my list, HOWEVER if I hit the "step_in" button after the execution of Enqueue I go into the Default Property's set method where Index = 1 and value = and it screws everything up, because the item that got shuffled to the end (index 1) gets overwritten by the item value shuffled to the top.
So basically the set method on the default property is getting called at what I think to be a completely ridiculous time. What gives? By the way I'm running VS2005 on XP.
Do you have a watch and/or are you executing a quick watch via a mouse-over that would read a property that might invoke the Set? If your debugging environment evaluates something that changes data, you can get weird behavior like what you're describing.
Whether or not the case above is true, if multiple threads can write to Members, consider using ReaderWriterLockSlim.
No answer. Never fixed this, just worked around it.

Windows Forms with async socket; no text output

Currently I am having a weird problem which I simply do not understand. I have a simple GUI, with one button & one richeditbox. I have an async socket running, I am receiving some data over the network which I want to print to the gui(richeditbox). The async socket is being started when the user hits the button. So when I receive the network data I call a function which prints the data, here how it looks like (in form1 class):
Public Sub AddText(ByVal text As String)
Try
Console.WriteLine(text)
RichTextBox1.AppendText(text)
RichTextBox1.AppendText(vbNewLine)
Catch e As Exception
Console.WriteLine(e.ToString())
End Try
End Sub
Then I simply do Form1.AddText(..) from my network class or a module (does it matter?). The problem is that nothing appears in the richeditbox, even though the AddText function is being called, no exceptions, no errors, simply nothing. I've looked thru it with the debugger, and "text" contained the data it had to print, but simply nothing appears.. Anyone have an idea?
If the socket is running on another thread (which, of course, it is because it's asynchronous), you may have to use InvokeRequired in order to get the RichTextBox to display the text. I had a similar issue with a listener on an asynchronous serial port listener.
I'm pretty sure David is right. Here's an example.
Delegate Sub AddTextDelegate(ByVal text as String)
Public Sub AddText(ByVal text as String)
If Me.InvokeRequired Then
Me.Invoke(new AddTextDelegate(AddressOf Me.AddText), new object() { text })
Else
Try
Console.WriteLine(text)
RichTextBox1.AppendText(text)
RichTextBox1.AppendText(vbNewLine)
Catch e as Exception
Console.WriteLine(e.ToString())
End Try
End If
End Sub
The deal is that controls have to be updated on the thread they were created on. It sounds like the AddText() routine is being called in the context of your async socket's thread. The AddText() routine will behave like a recursive function. The first time it's called, the InvokeRequired property will be true. This will cause it to be called again via the Invoke() call, which takes care of marshaling the data to the correct thread. The second time it's called, InvokeRequired will be false, and the control will be updated.
Fixed. I couldn't use Form1 to call the functions, because it's a type, its like a new var there with its own memory, since its a diff thread. So when I checked InvokeRequired, it said false because that Form1 belongs to that Thread, and thus no text was being displayed because I didn't even see the form. So just made a global var such as Public myForm As Form1 and assigned myForm to Form1 in Form1_Load.