I always wanted a simple system that would show me how many minutes approximately are left while processing a long for-next-statement.
I tried do achieve this by creating a class.
At the start, I want to set how many for-nexts I have (-> setMax)
At each For-Next, I will tell the class that one of the for-nexts was done. (->addOneDone)
The class would then tell me how many minutes I still have to wait until the entire for-next-statement will be done.
I was pretty sure I made that quite ok, but something is still wrong.
I suspect it is the milliseconds to minutes conversion.
Would anybody try to help me find my mistake?
Thank you very much!
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private m_lMax&
Private m_lItemsDone&
Private m_lStart&
Private m_cMillisecondsAlreadyNeeded As Currency
Private m_lMinutesLeft&
Private m_lLastTick&
Public Sub setMax(ByVal uCount As Long)
m_lMax = uCount
m_lStart = GetTickCount()
End Sub
Public Sub addOneDone()
m_lItemsDone = (m_lItemsDone + 1)
Dim lTick&
lTick = GetTickCount
Dim lMillisecondsNeeded&
lMillisecondsNeeded = (lTick - m_lLastTick)
If (m_lLastTick > 0) Then
m_cMillisecondsAlreadyNeeded = (m_cMillisecondsAlreadyNeeded + lMillisecondsNeeded)
Dim lMillisecondsForOneItem&
lMillisecondsForOneItem = (m_cMillisecondsAlreadyNeeded / m_lItemsDone)
Dim lItemsLeft&
lItemsLeft = (m_lMax - m_lItemsDone)
Dim cMillisecondsLeftToBeDone As Currency
cMillisecondsLeftToBeDone = (lMillisecondsForOneItem * lItemsLeft)
Dim lMinutes&
lMinutes = MillisecondsToMinutes(cMillisecondsLeftToBeDone)
m_lMinutesLeft = lMinutes
End If
m_lLastTick = lTick
End Sub
Private Function MillisecondsToMinutes(ByVal uMilliseconds As Long) As Integer
Dim seconds As Double
seconds = uMilliseconds / 1000
Dim minutes As Double
minutes = seconds / 60
MillisecondsToMinutes = minutes
End Function
Public Property Get MinutesLeft() As Long
MinutesLeft = m_lMinutesLeft
End Property
I changed my code, and it works now:
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private m_lMax&
Private m_lItemsDone&
Private m_lStart&
Private m_cMillisecondsAlreadyNeeded As Currency
Private m_lMinutesLeft&
Public Sub setMax(ByVal uCount As Long)
m_lMax = uCount
m_lStart = GetTickCount()
End Sub
Public Sub addOneDone()
m_lItemsDone = (m_lItemsDone + 1)
Dim lTick&
lTick = GetTickCount
Dim lMillisecondsNeeded&
lMillisecondsNeeded = (lTick - m_lStart)
Dim dblMillisecondsForOneItem As Double
dblMillisecondsForOneItem = (lMillisecondsNeeded / m_lItemsDone)
Dim lItemsLeft&
lItemsLeft = (m_lMax - m_lItemsDone)
Dim cMillisecondsLeftToBeDone As Currency
cMillisecondsLeftToBeDone = (dblMillisecondsForOneItem * lItemsLeft)
Dim lMinutes&
lMinutes = MillisecondsToMinutes(cMillisecondsLeftToBeDone)
m_lMinutesLeft = lMinutes
End Sub
Private Function MillisecondsToMinutes(ByVal uMilliseconds As Long) As Integer
MillisecondsToMinutes = uMilliseconds / 1000 / 60
End Function
Public Property Get MinutesLeft() As Long
MinutesLeft = m_lMinutesLeft
End Property
Related
newbie here; Im trying to migrate my VB program to run in Tabs. so far I have been experimenting with creating Tabs at runtime with added controls. I figured out that I can create tabs and add controls at either FormLoad() or by an execute Button. However, I can not access those controls once the Tab is created. I can not get any info from a combo, text box either outside the created Tab. Here is a simple program that I manage to put together:
Public Class Form1
Inherits Form
Private tabControl1 As TabControl
Private tabPage1 As TabPage
Private tabPage2 As TabPage
Dim nm As String
Private Sub MyTabs()
Me.tabControl1 = New TabControl()
Me.tabPage1 = New TabPage()
Me.tabPage2 = New TabPage()
Dim txtBox1 As New Windows.Forms.TextBox With {.Parent = tabPage1}
Dim CalcButton As New Windows.Forms.Button With {.Parent = tabPage1}
CalcButton.Location = New Point(1572, 150)
CalcButton.Size = New Point(100, 50)
CalcButton.Text = "CALCULATE"
txtBox1.Location = New Point(1572, 258)
txtBox1.Size = New Point(70, 22)
txtBox1.Name = "Loc_num"
txtBox1.Text = "1"
nm = txtBox1.Text
Me.tabControl1.Controls.AddRange(New Control() {Me.tabPage1, Me.tabPage2})
Me.tabControl1.Padding = New Point(15, 10)
Me.tabControl1.Location = New Point(35, 25)
Me.tabControl1.Size = New Size(1800, 750)
' Selects tabPage1 using SelectedTab
Me.tabControl1.SelectedTab = tabPage1
Me.tabPage1.Text = "tabPage1"
Me.tabPage2.Text = "tabPage2"
Me.Size = New Size(2000, 900)
Me.Controls.AddRange(New Control() {Me.tabControl1})
AddHandler CalcButton.Click, AddressOf CalcButton_Click
End Sub
Private Sub CalcButton_Click()
Dim xx As Integer
Me.tabControl1.SelectedTab = tabPage1
xx = Convert.ToInt32(nm) ' IT KEEPS SHOWING A 1, EVENTHOU I CHANGED IT TO 4 WHEN FORM LOADS
MessageBox.Show(nm)
End Sub
Public Sub New()
MyTabs()
End Sub
Public Sub Main()
Application.Run(New Form1())
End Sub
End Class
Im not sure if its possible to continue of this path
Thanks for any help or comment
I'm trying to implement the newest yahoo weather API in a .NET application (the one we were using was discontinued in favor of this new one): https://developer.yahoo.com/weather/documentation.html#commercial
Their only examples are in PHP and Java. I've done my best to convert the Java example to .NET but I still am getting a "401 - Unauthorized" response. I've gone over my code several times and cannot find any problems so I'm hoping someone else will be able to see where I went wrong. Code is below.
Private Sub _WeatherLoader_DoWork(sender As Object, e As DoWorkEventArgs)
Try
Dim oauth As New OAuth.OAuthBase
Dim forecastRssResponse As query
Dim appId As String = My.Settings.YahooAppID
Dim consumerKey As String = My.Settings.YahooAPIConsumerKey
Dim yahooUri As String = String.Format("{0}?location=billings,mt&format=xml", YAHOO_WEATHER_API_BASE_ENDPOINT)
Dim oAuthTimestamp As Integer = oauth.GenerateTimeStamp()
Dim oAuthNonce As String = oauth.GenerateNonce()
Dim parameters As New List(Of String)
Try
parameters.Add(String.Format("oauth_consumer_key={0}", consumerKey))
parameters.Add(String.Format("oauth_nonce={0}", oAuthNonce))
parameters.Add("oauth_signature_method=HMAC-SHA1")
parameters.Add(String.Format("oauth_timestamp={0}", oAuthTimestamp.ToString()))
parameters.Add("oauth_version=1.0")
' Encode the location
parameters.Add(String.Format("location={0}", HttpUtility.UrlEncode("billings,mt", Encoding.UTF8)))
parameters.Add("format=xml")
' Sort parameters ascending
parameters = parameters.OrderBy(Function(item) item).ToList()
Dim i As Integer = 0
Dim builder As New StringBuilder()
Do While (i < parameters.Count())
builder.Append(String.Format("{0}{1}", If(i > 0, "&", String.Empty), parameters(i)))
i += 1
Loop
Dim signatureString As String = String.Format("GET&{0}&{1}", HttpUtility.UrlEncode(YAHOO_WEATHER_API_BASE_ENDPOINT, Encoding.UTF8), HttpUtility.UrlEncode(builder.ToString(), Encoding.UTF8))
Dim oAuthSignature As String = _CreateOauthSignature(signatureString)
Dim authorizationLine As String = String.Format("OAuth oauth_consumer_key={0}, oauth_nonce={1}, oauth_timestamp={2}, oauth_signature_method=HMAC-SHA1, oauth_signature={3}, oauth_version=1.0", consumerKey, oAuthNonce, oAuthTimestamp, oAuthSignature)
Dim forecastRequest As WebRequest = WebRequest.Create(yahooUri)
forecastRequest.Headers.Add("Authorization", authorizationLine)
forecastRequest.Headers.Add("Yahoo-App-Id", appId)
' Cast to HttpWebRequest to set ContentType through property
CType(forecastRequest, HttpWebRequest).ContentType = "text/xml"
Dim forecastResponse As WebResponse = forecastRequest.GetResponse()
If forecastResponse IsNot Nothing Then
Using responseStream As Stream = forecastResponse.GetResponseStream()
Dim rssDoc As New XmlDocument()
rssDoc.Load(responseStream)
forecastRssResponse = rssDoc.OuterXml().FromXml(Of query)()
End Using
e.Result = forecastRssResponse
End If
Catch ex As Exception
e.Result = Nothing
LoadingManually = False
End Try
Catch ex As Exception
modMain.SendDevErrorEmail(ex, "_WeatherLoader_DoWork in WeatherWidget", "Catch around dowork code in fired from refresh timer event in wether widget")
e.Result = Nothing
LoadingManually = False
End Try
End Sub
Private Function _CreateOauthSignature(baseInfo As String) As String
Dim secretKey As String = String.Format("{0}&", My.Settings.YahooAPIConsumerSecretKey)
Dim encoding As New System.Text.ASCIIEncoding()
Dim keyBytes As Byte() = encoding.GetBytes(secretKey)
Dim messageBytes As Byte() = encoding.GetBytes(baseInfo)
Dim hashMessage As Byte()
Using hmac As New HMACSHA1(keyBytes)
hashMessage = hmac.ComputeHash(messageBytes)
End Using
Return Convert.ToBase64String(hashMessage)
End Function
After painstakingly creating a Java app, pasting in the Java example and stepping through it I found that the issue is in a poorly implemented URL Decode function on the receiving end.
In the Java app, URL Encode uses upper case characters while in .NET HTTPUtility.URLEncode uses lower case characters. This is enough to throw off your signature and cause a 401 - Unauthorized error.
My solution was to create a string extension method that will URL Encode in upper case:
<Extension>
Public Function UppercaseURLEncode(ByVal sourceString As String) As String
Dim temp As Char() = HttpUtility.UrlEncode(sourceString).ToCharArray()
For i As Integer = 0 To temp.Length - 2
If temp(i).ToString().Equals("%", StringComparison.OrdinalIgnoreCase) Then
temp(i + 1) = Char.ToUpper(temp(i + 1))
temp(i + 2) = Char.ToUpper(temp(i + 2))
End If
Next
Return New String(temp)
End Function
Using this extension method my signature gets created exactly like the one in the Java app and I am able to retrieve the response.
Hope this helps other .net programmers with this issue!
I have the following property in my clsdata class:
Public Property Get PatientCount() As Long
PatientCount = UBound(maobjPatient)
End Property
I also have this function in my class:
Private Function CountNonEmptyLines(ByVal strfile As String) As Long
Dim intFile As Integer
Dim strLine As String
Dim lngcount As Long
intFile = FreeFile
Open strfile For Input As intFile
lngcount = 0&
Do While Not EOF(intFile)
Line Input #intFile, strLine
If Len(strLine) > 0 Then
lngcount = lngcount + 1
End If
Loop
Close #intFile
CountNonEmptyLines = lngcount
End Function
the code of InputData is the following:
Public Sub InputData()
Dim blnLoaded As Boolean
Dim path As String
Dim file As String
Dim lnglines As Long
path = MyForm.TextPath
file = MyForm.TextFile
If LoadData(path, file) = False Then
MsgBox FileErrorString
Else
blnLoaded = LoadData(path, file)
End If
End Sub
and the code of LoadData is:
Private Function LoadData( _
ByVal strPath As String, _
ByVal strfile As String) _
As Boolean
Dim strPathFile As String
Dim lngRows As Long
LoadData = False
EraseData
InitialiseState
strPathFile = strPath & "\" & strfile
If Not FileExists(strPathFile) Then
Exit Function
End If
lngRows = CountNonEmptyLines(strPathFile)
If lngRows = 0 Then
Exit Function
End If
If Not LoadPatientLines(strPathFile, lngRows) Then
Exit Function
End If
mFileError = leNOERROR
LoadData = True
End Function
In my form I have a button which loads some data from a file:
Private Sub CmdLoad_Click()
Dim myData As New clsData
Call myData.InputData
End Sub
I also have a textbox:
Private Sub TextEntries_Change()
End Sub
How can I have the value of PatientCount or the lngcount from countnonemptylines function, in my textbox when I click CmdLoad, something like TextEntries.text=...?
As follow up from comments, this one works:
TextEntries.text = myData.PatientCount
This is probably a newbie mistake where I'm not aware of some setting that I haven't changed. Anyways, I'm trying use Dictionary to store a instances of class I've created.
Class cls_Connote is just a container of details.
Public connoteNumber As String
Public despatchDate As Date
Public carrier As String
Public service As String
Public items As Integer
Public weight As Integer
Public cost As Single
Public surchargeType As String
Here is how I'm storing the details into the class then into the dictionary.
Function getSurcharge_tag(givenTag As String, givenCol As String, ByRef dicStore As Dictionary, ByRef counter As Integer)`
Dim tagLen As Integer
Dim conNum, conTag As String
Dim clsSurchargeDetails As New cls_Connote
Dim despatchDate, carrier As String
Dim items, weight As Integer
Dim cost As Single
Range(givenCol).Select
tagLen = Len(givenTag)
Do While (ActiveCell.Value <> "")
conNum = Mid(ActiveCell.Value, 1, Len(ActiveCell.Value) - 1)
conTag = Mid(ActiveCell.Value, Len(ActiveCell.Value) - tagLen + 1, Len(ActiveCell.Value))
If (conTag = givenTag) Then 'Remove: both the Original and Adjusted connote lines
despatchDate = ActiveCell.Offset(0, -2).Value
items = ActiveCell.Offset(0, 10).Value
weight = ActiveCell.Offset(0, 11).Value
cost = ActiveCell.Offset(0, 12).Value
clsSurchargeDetails.connoteNumber = conNum
clsSurchargeDetails.despatchDate = despatchDate
clsSurchargeDetails.carrier = carrier
clsSurchargeDetails.items = items
clsSurchargeDetails.weight = weight
clsSurchargeDetails.cost = cost
clsSurchargeDetails.surchargeType = givenTag
dicStore.Add conNum, clsSurchargeDetails
givenCtr = givenCtr + 1
ActiveCell.EntireRow.Delete
Else
ActiveCell.Offset(1, 0).Select
End If
Loop
End Function
This is how I'm trying to get the connotes out of the Dictionary.
Function displaySurcharges(wrkShtName As String, ByRef dicList As Dictionary)
'Remove the existing worksheet
Dim wrkSht As Worksheet
On Error Resume Next
Set wrkSht = Sheets(wrkShtName)
On Error GoTo 0
If Not wrkSht Is Nothing Then
Worksheets(wrkShtName).Delete
End If
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = wrkShtName
populateColumnHeaders
Range("A2").Select
Dim getCon As cls_Connote
Set getCon = New cls_Connote
Dim vPtr As Variant
Dim ptrDic As Integer
For Each vPtr In dicList.Keys
Set getCon = dicList.Item(vPtr)
ActiveCell.Value = getCon.connoteNumber
ActiveCell.Offset(0, 1).Value = getCon.despatchDate
ActiveCell.Offset(0, 2).Value = getCon.carrier
ActiveCell.Offset(0, 12).Value = getCon.items
ActiveCell.Offset(0, 13).Value = getCon.weight
ActiveCell.Offset(0, 15).Value = getCon.cost
ActiveCell.Offset(0, 16).Value = getCon.surchargeType
Set getCon = Nothing
ActiveCell.Offset(1, 0).Select
Next vPtr
End Function
I can see dicList does contain different details, getCon only gets the last entry in the Dictionary.
Any help would be fantastic !
To avoid reusing and adding the same reference within the loop, when you need a new instance (after If (conTag = givenTag)) just ask for one:
Set clsSurchargeDetails = New cls_Connote
I'm playing with using the Rx in an XNA proof-of-concept, and I've run into a bit of an obstacle composing some queries that I'm hoping you folks can assist me with understanding how some of these operators work.
In my POC, I would like the player's score to increment only while there is not an active drag operation occurring. In addition, there is a 'grab gauge' that I would like to deplete whenever there is an ongoing drag, and fill whenever there isn't. Finally, if a drag operation is under way and the grab gauge drops below 0, I want to cancel the drag operation.
I've got the score incrementing working just fine with this:
IObservable<bool> PrincessGrabbed; // e.g., OnGrabbedBegin
_playerScoreChanged = IObservable<Unit>
// ... //
// In the initialization method
_playerScoreChanged = from startTrigger in PrincessGrabbed.StartWith(false)
.Where(x => !x)
from i in Observable.Interval(TargetElapsedTime)
.TakeUntil(PrincessGrabbed
.Where(x => x)
select new Unit();
_playerScoreChanged.Subscribe(unit => PlayerScore += 1);
The score will increment when it is supposed to, and stop when the character is picked up. Getting the gauge behavior to work correctly has been troublesome however. I've tried a ton of variations using Window, Generate, etc... but what seems to end up happening is that either it doesn't work at all, or the increment/decrement gauge operations end up fighting each other, or it will all seem to work properly, but continue to subtract or add points/gauge in the background. Here's the gauge implementation (extremely poor performance, crashes after about 10-15s, doesn't work properly):
var a = from startTrigger in PrincessGrabbed.StartWith(false).Where(x => x)
from i in Observable.Interval(TargetElapsedTime)
.Where(x => GrabGaugeFillAmount > 0)
.TakeUntil(PrincessGrabbed.Where(x => !x))
select new Unit();
a.TimeInterval().Subscribe(unit =>
GrabGaugeFillAmount -= (float)unit.Interval.TotalSeconds *
GrabGaugeDepletionPerSecond);
I have no doubts that my lack of understanding with Rx is at fault in some way, shape, or form, but I've reached the limit of experimenting with different operators/queries. Any insights?
EPILOGUE: Gideon Engelberth's answer fit my needs spot-on - I wish I could upvote it 10x! Here's the quick C# representation of his answer (not 100% on the IDisposable.Dispose(), but should be close):
public class AlternatingSubject : IDisposable
{
private readonly object _lockObj = new object();
private int _firstTriggered;
private readonly ISubject<Unit> _first = new Subject<Unit>();
public ISubject<Unit> First { get { return _first; }}
private readonly ISubject<Unit> _second = new Subject<Unit>();
public ISubject<Unit> Second { get { return _second; }}
public void TriggerFirst()
{
if (System.Threading.Interlocked.Exchange(ref _firstTriggered, 1) == 1)
return;
First.OnNext(Unit.Default);
}
public void TriggerSecond()
{
if (System.Threading.Interlocked.Exchange(ref _firstTriggered, 0) == 0)
return;
Second.OnNext(Unit.Default);
}
#region Implementation of IDisposable
public void Dispose()
{
lock (_lockObj)
{
First.OnCompleted();
Second.OnCompleted();
}
}
#endregion
}
And the logic to hook up the events in the game class (there are some refactoring opportunities). Summary: works like a charm! Thanks!
public class PrincessCatcherGame : Game
{
// ... //
public IObservable<bool> PrincessGrabbed // external source fires these events
{
get
{
return princessGrabbed.AsObservable();
}
}
// ... //
private readonly ISubject<bool> _princessGrabbed = new Subject<bool>();
private readonly ISubject<Unit> _grabGaugeEmptied = new Subject<Unit>();
private readonly ISubject<Unit> _grabGaugeFull = new Subject<Unit>();
private readonly AlternatingSubject _alternatingSubject = new AlternatingSubject();
private ISubject<Unit> _grabs;
private ISubject<Unit> _releases;
// ... //
private void SubscribeToGrabbedEvents()
{
var decrements = from g in _grabs
from tick in Observable.Interval(TargetElapsedTime).TakeUntil(_releases)
select Unit.Default;
decrements.Subscribe(x =>
{
Debug.Assert(GrabGaugeFillAmount >= 0);
GrabGaugeFillAmount -= (GrabGaugeDepletionPerSecond/30f);
if (GrabGaugeFillAmount <= 1)
{
GrabGaugeFillAmount = 0;
_alternatingSubject.TriggerSecond();
_grabGaugeEmptied.OnNext(Unit.Default);
}
});
decrements.Subscribe(x => PlayerScore += 1);
var increments = from r in _releases
from tick in Observable.Interval(TargetElapsedTime).TakeUntil(_grabs.Merge(_grabGaugeFull))
select Unit.Default;
increments.Subscribe(x =>
{
Debug.Assert(GrabGaugeFillAmount <= 100);
GrabGaugeFillAmount += (GrabGaugeFillPerSecond/30f);
if (GrabGaugeFillAmount >= 100)
{
GrabGaugeFillAmount = 100;
_grabGaugeFull.OnNext(Unit.Default);
}
});
}
You are definitely on the right track. I would start by making grabs and releases observables of their own and then making PrincessGrabbed based on those two observables. For a case like this, I use a class I call AlternatingSubject.
Public NotInheritable Class AlternatingSubject
Implements IDisposable
'IDisposable implementation left out for sample
Private _firstTriggered As Integer
Private ReadOnly _first As New Subject(Of Unit)()
Public ReadOnly Property First As IObservable(Of Unit)
Get
Return _first
End Get
End Property
Private ReadOnly _second As New Subject(Of Unit)()
Public ReadOnly Property Second As IObservable(Of Unit)
Get
Return _second
End Get
End Property
Public Sub TriggerFirst()
If System.Threading.Interlocked.Exchange(_firstTriggered, 1) = 1 Then Exit Sub
_first.OnNext(Unit.Default)
End Sub
Public Sub TriggerSecond()
If System.Threading.Interlocked.Exchange(_firstTriggered, 0) = 0 Then Exit Sub
_second.OnNext(Unit.Default)
End Sub
End Class
Along with that, you will probably want to add a "gague full" observable you can trigger from the incrementing method. The "gague empty" will trigger the release portion of the AlternatingSubject.
Sub Main()
Dim alt As New AlternatingSubject
Dim grabs = alt.First
Dim releases = alt.Second
Dim isGrabbed As New Subject(Of Boolean)()
'I assume you have these in your real app,
'simulate them with key presses here
Dim mouseDowns As New Subject(Of Unit)
Dim mouseUps As New Subject(Of Unit)
Dim gagueFulls As New Subject(Of Unit)()
'the TakeUntils ensure that the timers stop ticking appropriately
Dim decrements = From g In grabs
From tick In Observable.Interval(TargetElapsedTime) _
.TakeUntil(releases)
Select Unit.Default
'this TakeUnitl watches for either a grab or a gague full
Dim increments = From r In releases
From tick In Observable.Interval(TargetElapsedTime) _
.TakeUntil(grabs.Merge(gagueFulls))
Select Unit.Default
'simulated values for testing, you may just have
'these be properties on an INotifyPropertyChanged object
'rather than having a PlayerScoreChanged observable.
Const GagueMax As Integer = 20
Const GagueMin As Integer = 0
Const GagueStep As Integer = 1
Dim gagueValue As Integer = GagueMax
Dim playerScore As Integer
Dim disp As New CompositeDisposable()
'hook up IsGrabbed to the grabs and releases
disp.Add(grabs.Subscribe(Sub(v) isGrabbed.OnNext(True)))
disp.Add(releases.Subscribe(Sub(v) isGrabbed.OnNext(False)))
'output grabbed state to the console for testing
disp.Add(isGrabbed.Subscribe(Sub(v) Console.WriteLine("Grabbed: " & v)))
disp.Add(gagueFulls.Subscribe(Sub(v) Console.WriteLine("Gague full")))
disp.Add(decrements.Subscribe(Sub(v)
'testing use only
If gagueValue <= GagueMin Then
Console.WriteLine("Should not get here, decrement below min!!!")
End If
'do the decrement
gagueValue -= GagueStep
Console.WriteLine("Gague value: " & gagueValue.ToString())
If gagueValue <= GagueMin Then
gagueValue = GagueMin
Console.WriteLine("New gague value: " & gagueValue)
alt.TriggerSecond() 'trigger a release when the gague empties
End If
End Sub))
disp.Add(decrements.Subscribe(Sub(v)
'based on your example, it seems you score just for grabbing
playerScore += 1
Console.WriteLine("Player Score: " & playerScore)
End Sub))
disp.Add(increments.Subscribe(Sub(v)
'testing use only
If gagueValue >= GagueMax Then
Console.WriteLine("Should not get here, increment above max!!!")
End If
'do the increment
gagueValue += GagueStep
Console.WriteLine("Gague value: " & gagueValue.ToString())
If gagueValue >= GagueMax Then
gagueValue = GagueMax
Console.WriteLine("New gague value: " & gagueValue)
gagueFulls.OnNext(Unit.Default) 'trigger a full
End If
End Sub))
'hook the "mouse" to the grab/release subject
disp.Add(mouseDowns.Subscribe(Sub(v) alt.TriggerFirst()))
disp.Add(mouseUps.Subscribe(Sub(v) alt.TriggerSecond()))
'mouse simulator
Dim done As Boolean
Do
done = False
Dim key = Console.ReadKey()
If key.Key = ConsoleKey.G Then
mouseDowns.OnNext(Unit.Default)
ElseIf key.Key = ConsoleKey.R Then
mouseUps.OnNext(Unit.Default)
Else
done = True
End If
Loop While Not done
'shutdown
disp.Dispose()
Console.ReadKey()
End Sub
For the sake of the test app, everything is in one function. In your real app, you should of course consider what to expose and how.