Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
My app's external processes each poll a boolean to see if there is work to do. I now want to check that variable in a Timer event to cut down the 'not responding' messages.
A Timer object has to be placed on a form, which seems to cause some limitations.
Launching the event from a form with Me.Show (vbModal) works great. Only I don't want to actually show that form, I just want to use the timer. Trying to hide the form using Me.Hide then loses the Modal behavior which I need, so that's not a good workaround.
I tried launching the event from a class but it exhibits the same unwanted behavior as Me.Hide: Processing returns to the caller rather than staying in the timer event sub waiting for work.
Is there any way to implement an event based on Timer which doesn't require showing a form and does not immediately return to the caller? The external processes have no screen IO and none is desired.
You can look into using the SetTimer function from the Windows API. Add the following code in a Module and user TimerStart with an interval in milliseconds:
Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public Function TimerStart(ByVal p_lngInterval As Long) As Long
' Start timer
TimerStart = SetTimer(0, 0, p_lngInterval, AddressOf TimerCallBack)
End Function
Public Sub TimerCallBack(ByVal hwnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)
' Handle your polling here
End Sub
You do not need a Form so this should suit your needs.
You can also use Sleep from the Windows API in conjuction with Timer to keep your EXE running:
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Public Sub Main()
TimerStart 2000
Do While True
DoEvents
Sleep 1000
Loop
End Sub
See these other answers for more details:
How to make safe API Timers in VBA?
How do I delay code execution in Visual Basic (VB6)?
Related
I'd like to display the data of my Access database on a separate monitor for the students of a library.
What software or Access tool should I use for this please?
The database should be the only thing the students have access to, meaning they can't access other apps on the computer.
Thank you very much for your time.
Firstly: relying on your Access app being on the separate monitor is NOT AT ALL secure if you need to prevent user access to other applications (for so, so many reasons, but press Windows+E for an example).
Secondly: Microsoft Access will open up on the same monitor on which it was last open. Though I assume you know that and wouldn't be asking if that were suitable to you.
Thirdly: here is VBA code that actually moves the Access application window. It DOES NOT determine where the second monitor is - you have to change the value -1500 according to the screen specs (either manually and hard-coded, or better, Google for some code to determine the position of the second monitor). On my setup, it -1500 happens to end up around the middle of the second monitor which I happen to have on the left (possibly unusual?). If your second monitor is on the right, then I think you'll need a positive value that is greater than the resolution of the fist monitor. It just has to be somewhere within the second screen - not necessary perfectly on the edge because the code then maximises the window. Upshot: you need to experiment with that.
What it does:
Take window out of maximised mode (necessary to move it properly).
Move it such that the top-left corner is somewhere in the second screen.
Maximise the window.
VBA:
Declare Function winapi_ShowWindow Lib "user32" Alias "ShowWindow" (ByVal hwnd As Long, ByVal nCmd As Long) As Long
Declare Function winapi_MoveWindow Lib "user32" Alias "MoveWindow" (ByVal hwin As Long, ByVal X As Long, ByVal Y As Long, ByVal dx As Long, ByVal dy As Long, ByVal fRepaint As Long) As Long
Const SW_SHOWNORMAL = 1
Const SW_SHOWMAXIMIZED = 3
Public Sub MoveAccessWindow
winapi_ShowWindow Access.Application.hWndAccessApp, SW_SHOWNORMAL
winapi_Movewindow Access.Application.hWndAccessApp , -1500, 0, 1000, 1000, True
winapi_ShowWindow Access.Application.hWndAccessApp, SW_SHOWMAXIMIZED
End Sub
I have a follow-on question about this question:
How to dynamically create a background worker in VB.net
I'm afraid I don't understand how DirectCast would solve my problem. I am creating an array of backgroundworkers: bWorker(0), bWorker (1), etc. each one creates a new form which is also in an array: page(0), page(1) etc.
The background workers need to 'know' their index number so that they can create the appropriate page (which is a form). As I mentioned before, I have found a system that works. I put the backgroundworkers' hashcodes in an array which I use to retrieve their index numbers. It just feels a bit clunky and maybe using DirectCast would be better but I don't understand how.
BackgroundWorker.RunWorkerAsync has two overloads. See BackgroundWorker.RunWorkerAsync(Object).
Now you can pass a variable and get it on BackgroundWorker.DoWork using DoWorkEventArgs.Argument.
Dim BackgroundWorker1 As New System.ComponentModel.BackgroundWorker
AddHandler BackgroundWorker1.DoWork, AddressOf BackgroundWorker_DoWork
Dim BackgroundWorker2 As New System.ComponentModel.BackgroundWorker
AddHandler BackgroundWorker2.DoWork, AddressOf BackgroundWorker_DoWork
' I'm going to pass integers, but you can pass whatever you want.
BackgroundWorker1.RunWorkerAsync(0)
BackgroundWorker2.RunWorkerAsync(1)
Private Sub BackgroundWorker_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs)
Select Case e.Argument
Case 0
' Form1
Case 1
' Form2
End Select
End Sub
I have found the solution. The problem I had with the e.Argument system was that it only applied to DoWork. I use RunWorkerCompleted to show the form created (if I try to show it with DoWork things go badly wrong). RunWorkerCompleted has no e.Argument property. My solution is to do this: e.Result = e.Argument in DoWork because e.Result is available in RunWorkerCompleted.
I need read in an infinite loop some variables and in the case it changes the boolean status it must do something.
I tried to use a Do...Loop but the application crashes.
Is there a way in visual basic 6 to use an infinite loop without stunk?
My code:
Do
asd1 = readValue1
asd2 = readValue2
If asd1 <> asd1ex Then
Text1.Text = "yes"
End If
If asd2 <> asd2ex Then
Text1.Text = "no"
End If
Loop While True
Make a timer and on that timer check the status, instead of the loop.
Solved after comment that explained where the data was coming from (async COM component's property):
working with vb6 IDE on a realtime client-server project. I have to read some variables
and when one of these changes status it sends a socket message to
server. With the sleep it stuck equally
What did not help:
DoEvents and sleep
DoEvents
Sleep 100
might help, will need to refer to the windows function sleep. But VB6 is single thread (well one for UI and one for logic) so you should have a way to get out of the loop. What are you really trying to do? Can you describe at a top level?
Are you working on the VB6 IDE or in VBA code in Office?
For sleep to work declare:-
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
See this too https://stackoverflow.com/a/4540553/1643558
If your showing a form to the user to read value 1 and 2 then you can use a modal form and have a button to click when they are done, and hide the form only when you like the values. No need to have a loop then. Can show an error MsgBox on a modal form too.
See http://www.tek-tips.com/viewthread.cfm?qid=1117372
Maybe remove the sleep and only keep the DoEvents.
You could also make a timer and on that timer check the status, instead of the loop
It looks like you're trying to set up a sort of event handler. In effect, your loop is "listening" for a change to the variable. You don't explain how the variables get changed, and this is important . If whatever is changing the variables can also raise an event, then you're home free--you can get rid of your loop and use the event handler to send the socket message. (This is probably why Deanna asked how the variables change.) This is the preferred way to do what you want, so you should find ways to raise an event if the variables change.
I’m new to Visual Basic 6, so please be patient (and thorough with your answers).
I’m building a form and I need to check if the information entered in one of its fields is numeric, otherwise the program has to beep.
The field is part of an array of controls and it is named txtMyField(0)
Last thing in my code I’ve written:
Private Sub txtMyField_Change(Index As Integer)
If Not IsNumeric(txtMyField(0).Text) Then
Beep
End If
End Sub
I don’t know if this code is correct and I don’t how to call the Sub to use it in order to check the field’s value before inserting in database.
Thanks a lot for your help!
You can do this by using the Validate event. You need to ensure that the CausesValidation property is true, if it is then the Validate event will be raised for that control.
Your event might look something like this:
Private Sub txtMyField_Validate(Index As Integer, Cancel As Boolean)
If Not IsNumeric(txtMyField(Index).Text) Then
Beep
Cancel = True
End If
End Sub
This would ensure that all the controls in your control array are numeric (given that their CausesValidation property is set to True at startup). If one of the controls is empty or contains non-numeric characters you will get a Beep when the control loses focus.
Note some things here
Sounding a Beep is not really a good way to indicate a validation error. A messagebox or textbox in the form to display the error is usually a better way. The user may not hear your beep or may not understand that "a beep" means "you need to provide a number in this field".
Your code referenced control with index = 0. The event may fire for any of the controls in the control array, so checking the value of control(0) is not really a logical thing to do when you should be validating control(5) (for example).
instead of beeping you could also make your texbox only accept certain keys
for example a textbox which will only accept numeric keys and the backspace key :
Private Sub Text1_KeyPress(KeyAscii As Integer)
KeyAscii = NrOnly(KeyAscii)
End Sub
Private Function NrOnly(intKey As Integer)
Dim intReturn As Integer
intReturn = intKey
Select Case intKey
Case vbKeyBack
Case vbKey0 To vbKey9
Case Else
intReturn = 0
End Select
NrOnly = intReturn
End Function
you can add more intelligence to the NrOnly function to allow more keys, or check for certain boundaries
be careful though as the user can still use the mouse to input other data via copy&paste
In my WPF applciation I would like to use global variable, the purpose is like to store the current user information etc, The problem is that, there are two methods for it and they are:
Application.Current.Properties vs My.Settings
I know that using My.Settings, the changes will be stored and when the app restarts or reopened, they would load the last saved ones, I dont want it this way. Could you please clarify is Application.Current.Property solve my problem or is there any other method for this.
Thank you.
Why not just create a static or singleton class to hold all your values, if your going to reload them every time the program is going to run anyway?
Public Class Globals
Public Shared Property One As String
Get
Return TryCast(Application.Current.Properties("One"), String)
End Get
Set(value As String)
Application.Current.Properties("One") = value
End Set
End Property
Public Shared Property Two As Integer
Get
Return Convert.ToInt32(Application.Current.Properties("Two"))
End Get
Set(value As Integer)
Application.Current.Properties("Two") = value
End Set
End Property
End Class