I developing an application that require pass the timer value to next form. For example Form A time out is 30 seconds, If the user dont click on the screen, it will back to the Main Screen. Sames go to the Form B. Please help. Thanks
You need to modify the constructor(s) of the page(s) you want to accept the timer value, like this:
Public Class FormA Inherits Form
Private timerValue As Integer
Public Sub New(_timerValue As Integer)
timerValue = _timerValue
End Sub
Public Sub MethodA
' Do something with timerValue here
End Sub
End Class
Related
My first post here.
I have c# .dll, to use with a scanner.
I intend to use it with some legacy vb6 applications.
The .dll raises an event with the scanned code using RaiseArgs.
I am trying to write an .ocx library for use with VB6 apps.
To catch this event in an .ocx library I am trying to adapt this code:
Sub TestEvents()
Dim Obj As New Class1
' Associate an event handler with an event.
AddHandler Obj.Ev_Event, AddressOf EventHandler
' Call the method to raise the event.
Obj.CauseSomeEvent()
' Stop handling events.
RemoveHandler Obj.Ev_Event, AddressOf EventHandler
' This event will not be handled.
Obj.CauseSomeEvent()
End Sub
Sub EventHandler()
' Handle the event.
MsgBox("EventHandler caught event.")
End Sub
Public Class Class1
' Declare an event.
Public Event Ev_Event()
Sub CauseSomeEvent()
' Raise an event.
RaiseEvent Ev_Event()
End Sub
End Class
But I am getting
Invalid use of AddressOf operator error when I call: AddHandler Obj.Ev_Event, AddressOf EventHandler
What could be probable cause of this error?
I suspect, that i am not going in the right direction with solving this task, so would it be a better way to approach this problem?
You have a mix of VB6 and VB.NET I think. In VB6, if you want to add an event handler for event on an object that you create yourself (as opposed to being added with the Forms designer) you would do it something like this:
Private WithEvents mObjectThatHasEvents As Class1
Private Sub StartListeningToEvents()
If mObjectThatHasEvents Is Nothing Then
Set mObjectThatHasEvents = New Class1
End If
End Sub
Private Sub TriggerEvent()
mObjectThatHasEvents.CauseSomeEvent
End Sub
'Assumes that Class1 has an event called "MyEvent".
Private Sub mObjectThatHasEvents_MyEvent()
MsgBox("EventHandler caught event.")
End Sub
Private Sub StopListeningToEvents()
Set mObjectThatHasEvents = Nothing
End Sub
If you need to keep the event source object alive while not listening to its events, you will need a second reference to it via a variable that is not "WithEvents".
I should point out that the VB6 IDE will recognize the event source. In the code pane, use the dropdowns at the top to select the object and event. The IDE will stub them out for you automatically (just like buttons or anything else).
tcarvin pretty much explained what you have to do but here's your code, adjusted:
Private WithEvents mObjWithEvents As Class1
Sub TestEvents()
Dim Obj As New Class1
Set mObjWithEvents = Obj
' Call the method to raise the event.
Obj.CauseSomeEvent
' Stop handling events.
Set mObjWithEvents = Nothing
' This event will not be handled.
Obj.CauseSomeEvent
End Sub
Private Sub mObjWithEvents_EvEvent()
' Handle the event.
MsgBox ("EventHandler caught event.")
End Sub
And your Class1:
Public Event EvEvent()
Public Sub CauseSomeEvent()
' Raise an event.
RaiseEvent EvEvent
End Sub
Notice that Ev_Event was renamed to EvEvent.
I have this Sub which does the calculation get the information from CSV file.
Private Sub getTotalAmt(intDuration As integer, strProgrameType As String)
I've another Sub:
Private Sub getMembershipDiscount(ByRef dtDOB As Date, dblTotalAmt as Double)
which calculates the age of the customer and based on their age, gives them discount. So to do this, I've got to get the total amount from the above Sub (getTotalAmt) to this Sub procedure.
My question is, how to receive total amount from that sub procedure?
by definition, subroutines don't have output.
Instead, you want to write a function. In your case, change the code you have to something like this:
private function getTotalAmt(intDuration As integer, strProgrameType As String) as double
'do the same maths you do in the sub, and store your answer in a variable called "whatever"
getTotalAmt = whatever
end function
then to use the function:
sub IUseFunctions()
dim myDiscount as double
myDiscount = getTOtalAtm(1,"s")
end sub
In this example case, I've decided for you that the discount value is stored in a double type number. You can change that to whatever you like, at the top line of the getTotalAmt function.
Please speicify return types and convert your Sub to a Function
In that way you can always return something from your Functions,
if you specify a return type to your getTotalAmt(int Duration As Integer, StrProgrameType As String) method , That would be look like this Function getTotalAmt(int Duration As Integer, StrProgrameType As String) As double
then from another method you can call it and use retuned value of it for further calculation or whatever.
i.e
Private Sub sub1()
//You use the Sub2's value in here like
msgbox(sub2)
End Sub
Private Function sub2() As String //You can specifiy any data type you are returning, I specified String just for demnostrate
//Set the value of Sub2 in here
sub2 = "Yourvalue";
End Function
Here's what I've got on a command button; it's just creating variables and attempting to output their ID (which should be an instance variable inherited from the base class.)
Private Sub Command1_Click()
Dim ball1 As Ball, ball2 As Ball
Dim cube1 As Cube, cube2 As Cube
Set ball1 = New Ball
Set cube1 = New Cube
Set cube2 = New Cube
Set ball2 = New Ball
MsgBoxTheID (ball1) 'errors; should be 0
MsgBoxTheID (ball2) 'errors; should be 3
MsgBoxTheID (cube1) 'errors; should be 1
MsgBoxTheID (cube2) 'errors; should be 2
Call ball1.MsgBoxID ' works; displays 0
Call ball2.MsgBoxID ' works; displays 3
Call cube1.MsgBoxID ' works; displays 1
Call cube2.MsgBoxID ' works; displays 2
End Sub
Modeul1.bas:
Global globalID As Integer
Public Sub MsgBoxTheID(theObj As BaseObj)
' this function is meant to accept objects of type Ball, Cube, and BaseObj
MsgBox theObj.ID
End Sub
BaseObj Class Module:
Public ID As Integer
Public isVisible As Boolean
Public Sub setVisiblity(newVis As Boolean)
isVisible = newVis
End Sub
Public Sub MsgBoxID()
MsgBox ID
End Sub
Private Sub Class_Initialize()
ID = globalID
globalID = globalID + 1
End Sub
Ball Class Module:
Implements BaseObj
Private theObj As BaseObj
Public radius As Double
Private Property Let BaseObj_ID(ByVal RHS As Integer)
End Property
Private Property Get BaseObj_ID() As Integer
End Property
Private Property Let BaseObj_isVisible(ByVal RHS As Boolean)
End Property
Private Property Get BaseObj_isVisible() As Boolean
End Property
Public Sub MsgBoxID()
Call theObj.MsgBoxID
End Sub
Private Sub BaseObj_MsgBoxID()
Call theObj.MsgBoxID
End Sub
Public Sub BaseObj_setVisiblity(newVis As Boolean)
End Sub
Private Sub Class_Initialize()
Set theObj = New BaseObj
End Sub
Cube Class Module:
Implements BaseObj
Private theObj As BaseObj
Public sideLength As Double
Private Property Let BaseObj_ID(ByVal RHS As Integer)
End Property
Private Property Get BaseObj_ID() As Integer
End Property
Private Property Let BaseObj_isVisible(ByVal RHS As Boolean)
End Property
Private Property Get BaseObj_isVisible() As Boolean
End Property
Public Sub MsgBoxID()
Call theObj.MsgBoxID
End Sub
Private Sub BaseObj_MsgBoxID()
Call theObj.MsgBoxID
End Sub
Public Sub BaseObj_setVisiblity(newVis As Boolean)
End Sub
Private Sub Class_Initialize()
Set theObj = New BaseObj
End Sub
There are several things I don't like about this, two of which I am of the impression are unavoidable: (1) the fact that it's a mess compared to C++, and (2) the fact that the Ball and Cube classes merely contain an object of BaseObj type. They are not actually inheriting anything from BaseObj; they are only being forced to implement the same interface (whoopty doo.)
To make matters worse, and this is the one that I am truly hoping is rectifiable, they do not seem to be able to fill in for an object of the base class when it comes to parameter passing.
Am I doing something wrong?
Visual Basic 6 is not the ideal language with which to learn the "purer" form of OOP. VB6 was designed to implement a very much hybridized version of object-based programming that orbited the Microsoft Component Object Model (COM) world, with its interface inheritance orientation. VB6 does not support implementation inheritance, which tends to make the kind of polymorphism you're looking for hard to do.
There are a few tricks I recall from the VB6 era to "get around" (sort of) the implementation inheritance problem, particularly when it comes to substituting an object of a base class for a subclass. One trick I remember is to declare a property procedure of the type of the base interface that returns a reference to "Me" as the return type. That "tricks" the runtime into providing the conversion into the desired interface. There's another magic trick to make a property the "defaut" property by setting its "procedure number" to -4 in one of VB6's design dialogs.
The point? If you're really wanting to get into conventional OO programming, don't try to learn it with VB6 if you don't have to. Move up to (at least) VB.NET, C#, or Java. I don't say that as a VB6 hater - heck, knowing these stupid details paid the bills for a long time - but its a tough nut to crack to translate its own little idiosyncrasies into a good, fundamental understanding of OOP.
Good luck!
You've figured out how to fix the error, but I'll contribute the "why".
In VB6 (and VB5, etc), there are two syntaxes for invoking a method/function/subroutine/statement. The first is this:
MySubName arg1, arg2, arg3, arg4
Blech, I know it is my bias from C and Java, but I like to see parenthesis around my argument list. That sytax is this:
Call MySubName(arg1, arg2, arg3, arg4)
So those two are equivilent.
What you ran into is not the effect of the Call. What you ran into is the effect of the unneeded parenthesis in the non-Call version. The parenthesis force the statement/arg inside them to be evaluated before the rest of the statement (think math order of operation).
So this:
SomeSub (arg1)
Is like this:
temp = (arg1)
SomeSub temp
Further, objects in VB6 can have a "default property". This lets you write code like this:
Dim name as String
name = txtName
Instead of assigne the textbox object reference to name, the default property of .Text is used, and the result is like this:
Dim name as String
name = txtName.Text
So when you tried to evaluate SomeSub (arg1) I think it would attempt to locate and execute the default property of your object and pass that value to SomeSub.
Well, I figured it out, sort of.
MsgBoxTheID (ball1) 'errors; should be 0
MsgBoxTheID (ball2) 'errors; should be 3
MsgBoxTheID (cube1) 'errors; should be 1
MsgBoxTheID (cube2) 'errors; should be 2
...needs to be changed to...
Call MsgBoxTheID (ball1) 'errors; should be 0
Call MsgBoxTheID (ball2) 'errors; should be 3
Call MsgBoxTheID (cube1) 'errors; should be 1
Call MsgBoxTheID (cube2) 'errors; should be 2
... even though MsgBoxTheID has no return type, which is weird because I always thought Call was simply something that you could use to discard the return value without having to declare a variable, like so:
dim unneededVar as Integer
unneededVar = FunctionNameThatReturnsAnInteger()
But I guess not. So... I'll have to go read up on exactly what the Call statement is doing to make this example program work, but it's definitely working now. (I also had to add BaseObj_ID = theObj.ID to the Property Get BaseObj_ID() As Integer methods in the classes that were implementing BaseObj.)
I have developed a custom visual basic 6 control and declared a few custom events. Is it possible in vb6 to raise these events from a module or I need to implement a special "proxy" methods in my control to do this?
RaiseEvent:
Compile error:
Only valid in object module.
(Which makes sense.)
Yes, you need a Friend method on your class that you would call to raise events from your module:
Class:
Public Event Click()
Friend Sub OnClick()
RaiseEvent Click
End Sub
Module:
someVar.OnClick
Perhaps not entirely the answer you are looking for, but it is possible to use Event-like procedures from plain Modules:
First define a Callback Interface:
IEventsClient (Class Module):
Option Explicit
Public Sub PropertyChanged(sender As Object, property As String)
End Sub
MyModule:
Option Explicit
Public EventClients As Collection
Public Sub OnPropertyChanged(property As String)
Dim eventsClient As IEventsClient
Dim element As Variant
For Each element In EventClients
Set eventsClient = element
eventsClient.PropertyChanged MyControl, property
Next
End Sub
Public Sub RaiseSomePropertyChanged()
OnPropertyChanged "SomeProperty"
End Sub
The main Form:
Option Explicit
Implements IEventsClient
Private Sub Form_Load()
'Entry point of the application'
Set MyModule.EventClients = New Collection
MyModule.EventClients.Add Me
End Sub
Private Sub IEventsClient_PropertyChanged(sender As Object, property As String)
If TypeOf sender Is MyControl Then
Select Case property
Case "SomeProperty"
' DoSomething'
End Select
End If
End Sub
I have 2 classes, a parent and a child.
Class Test
Private Test_Text
Private Sub Class_Initialize()
Test_Text = "Hello"
End Sub
Private Sub Class_Terminate()
End Sub
Public Property Get Text
Text = Test_Text
End Property
Public Property Let Text(ByVal strIn)
Test_Text = strIn
End Property
End Class
Class SubTest
Public SubTest_Test
Private SubTest_Interger
Private Sub Class_Initialize()
Set SubTest_Test = New Test
End Sub
Private Sub Class_Terminate()
Set SubTest_Test = Nothing
End Sub
Public Property Get int
int = SubTest_Integer
End Property
Public Property Let int(ByVal intIn)
SubTest_Integer = intIn
End Property
End Class
Because I have made SubTest_Test public I can access it through the child class like this
Set MyTest = New SubTest
MsgBox MyTest.SubTest_Test.Text
Is this acceptable or should I make SubTest_Test private and write properties in the child class to access the parents properties?
Edit: I guess the question should have been, are there any security/usability issues with accessing the parent directly.
The more I think about it the more I think from a usability standpoint, it is better to hide the parent from anyone using the child class. That way when you are creating an object from the child class, you don't have to know anything about the parent class.
Since this is a HAS-A relationship between your two classes then I think you ought to leave it as is. You don't need to introduce encapsulating code for something that does not need it.
Here is a pseudo-code example:
class Engine
[method] start()
class Car
[property] Engine
Ideally you would want to reference Engine as a property of Car like so:
Car.Engine.start()
The alternative would be to write extra code in Car to wrap the methods in Engine. While you can do this it doesn't make much sense as you will be simply writing pass-through methods from Car to Engine.
no - this violates the Law of Demeter; rethink the interface - under what circumstances would someone need to access the Text property of the enclosed Test object in a SubTest object? If these situations make sense, you'll need to expose Text as a property in SubTest.
Given the names I would have expected SubTest to inherit from Test and thus automatically expose the Text property, but thankfully I have forgotten VBSCRIPT so I can't remember if it even supports inheritance ;-)
I'd say it depends on the number of properties you want to expose. But encapsulation is always a good rule to follow. If Text is the only property you'll be accessing, I'd most likely make SubTest_Test private and wrap the property.