I created a ProgressBar I want to display with % while my macro runs.
I tried the parameters UserForm1.Show vbModeless and UserForm1.Repaint in my main macro.
Private Sub UserForm_Activate()
Dim reminder As Long
Dim i As Long, j As Long
reminder = 0
For i = 1 To 200
UserForm1.Label2.Width = UserForm1.Label2.Width + 1
If i Mod 2 = 0 Then
reminder = reminder + 1
UserForm1.Caption1 = reminder & " % completed"
End If
For j = 1 To 150
DoEvents
Next j
Next i
Unload UserForm1
End Sub
The UserForm stops on 0% and my main macro runs to the end, then the UserForm with ProgressBar runs from 0 to 100% and closes.
WORKING:
I create two NON MODAL! Forms NAMED "progressbar"
( with 1 Textbox NAMED counter)
and "tester "
(with 3 Buttons NAMED count hide and show)
the code in progressbar:
Dim count As Long
Public Sub progressbar_show()
count = 0
progressbar.Show
End Sub
Public Sub progressbar_update()
If count < 100 Then count = count + 1
progressbar.counter.Text = Str(count)
DoEvents
End Sub
Public Sub progressbar_close()
counter = 0
progressbar.hide
End Sub
The code in tester: (calls routines in form progressbar)
Private Sub count_Click()
Call progressbar.progressbar_update
End Sub
Private Sub hide_Click()
Call progressbar.progressbar_close
End Sub
Private Sub show_Click()
Call progressbar.progressbar_show
End Sub
Works as designed.
on the click button the textbox will be updated on each click.
Please note HOW i call the functions from on form to the other form. The form name has to be included. The name of the controls have also to match. Its a good idea to rename the controls and forms. I made a autocad VBA with has 1700 controls. Its not the fun after some weeks
to imagine what commandbutton_762 actuelly may do ;)
That can not work like this. You need 3 functions
one to show the userform progressbar 0 percent.
then you need a function to update your form
end finaly the function to remove the form
This code is NOT tested see the testing code i posted here also !
Dim counter As Long
Public Sub UserForm_Activate()
counter = 0
UserForm1.Label2.Width =0
UserForm.show
End Sub
Public Sub UserForm_update()
if counter <100 then counter=counter+1
UserForm1.Label2.Width = counter
DoEvents
end sub
Public Sub UserForm_close()
counter = 0
UserForm.hide
End Sub
'somewhere in a module or class
sub calculate
call UserForm_Activate()
for i=0 to 100
call UserForm_update()
'whatever
' Sleep (200) if this very handy OS call is included somewhere
next
call UserForm_close
end sub
Related
I need the help with the selection of multiple checkboxes by user. I have a userform in vba that has 8 checkboxes. I want user to select only ONE checkbox at a time. What is the shortest coding possible?
Please, try the next way:
Create a Sub able to untick all the check boxes, except the active one:
Public Sub UnTickCheckBoxes() 'Public to be also called from outside if use a class for event allocation
Dim i As Long
For i = 0 To Me.Controls.count - 1
If TypeName(Me.Controls(i)) = "CheckBox" And Not ActiveControl.Name = Me.Controls(i).Name Then
Application.EnableEvents = False
Me.Controls(i).value = False
Application.EnableEvents = True
End If
Next i
End Sub
Call the above sub from the Click event of all check boxes. You can use Change event for doing something else. The call can be done in this way:
Private Sub CheckBox1_Click()
If ActiveControl.value = True Then
UnTickCheckBoxes
End If
End Sub
2 bis. Automatic event allocation to all check boxes:
2.1 Create a class named "chkBoxesClickEvent". Copy and paste in it the next code:
Option Explicit
Public WithEvents chkBEvent As MSForms.CheckBox
Private Sub chkBEvent_Click()
If chkBEvent.value = True Then
chkBEvent.Parent.UnTickCheckBoxes
End If
End Sub
2.2 Declare on top of the form (in the declarations area) the next variable:
Private chkB() As New chkBoxesClickEvent
2.3 Place the next code in the UserForm_Initialize event:
Private Sub UserForm_Initialize()
Dim C As MSForms.Control, k As Long
ReDim chkB(Me.Controls.count): k = 1
For Each C In Me.Controls
If TypeOf C Is MSForms.CheckBox Then
Set chkB(k).chkBEvent = C: k = k + 1
End If
Next
ReDim Preserve chkB(k - 1)
End Sub
Do not forget to clear all check boxes Click event, if any code inside...
Show the form a see how it works, then send some feedback.
I need some help with getting the right code to do the following:
I have 4 groups of radio buttons inside a frame in a userform
Each group is a simple Yes/No radio button
I have a textbox that I want to autofill with a score range of A-D depending on the # of "yes" radio buttons selected.
The "No" checkboxes really shouldn't do anything in regards to the textbox
Userform Name = TP_UF
Frame Name = fun_opt_frame
Option Button Name for "Yes" = fun_score_yes1-4
Textbox Name = fun_scorebox
Logic:
4 Yesses = A
3 Yesses = B
2 Yesses = C
1 Yes = D
It doesn't matter what order the yesses are selected, its a total count. I tried using code using the frame but not sure if that is the best way. The frame for these radio buttons isn't needed for any reason other then to perhaps make it easier to code. So I could throw out the frame if it's not necessary to get this working.
I am not sure where to start here. Any help would be appreciated.
pic
The quickest and easiest way for you to understand is - I guess - the following code. You have to put the code into the class module of the userform.
Option Explicit
Dim opt1 As Byte
Dim opt2 As Byte
Dim opt3 As Byte
Dim opt4 As Byte
Private Sub opt1Yes_Click()
opt1 = 1
EvalOpt
End Sub
Private Sub opt1No_Click()
opt1 = 0
EvalOpt
End Sub
Private Sub opt2yes_Click()
opt2 = 1
EvalOpt
End Sub
Private Sub opt2No_Click()
opt2 = 0
EvalOpt
End Sub
Private Sub opt3yes_Click()
opt3 = 1
EvalOpt
End Sub
Private Sub opt3No_Click()
opt3 = 0
EvalOpt
End Sub
Private Sub opt4yes_Click()
opt4 = 1
EvalOpt
End Sub
Private Sub opt4No_Click()
opt4 = 0
EvalOpt
End Sub
Private Sub EvalOpt()
Dim sumOpt As Byte
Dim res As String
sumOpt = opt1 + opt2 + opt3 + opt4
Select Case sumOpt
Case 1: res = "D"
Case 2: res = "C"
Case 3: res = "B"
Case 4: res = "A"
Case Else: res = ""
End Select
Me.fun_scorebox.text = res
End Sub
I assumed the option buttons are named opt1Yes, opt1No, opt2Yes, opt2No etc.
A more advanced solution would probably be to use classe modules and "collect" the option buttons in such a way.
I ended up going about this differently and I got it working using a counter. Thanks for the help! Posting code here in case anyone else needs it.
Option Explicit
Private Sub OptionButton1_Change()
set_counter
End Sub
Private Sub OptionButton2_Change()
set_counter
End Sub
Private Sub OptionButton3_Change()
set_counter
End Sub
Private Sub OptionButton4_Change()
set_counter
End Sub
Private Sub OptionButton5_Change()
set_counter
End Sub
Private Sub OptionButton6_Change()
set_counter
End Sub
Private Sub OptionButton7_Change()
set_counter
End Sub
Private Sub OptionButton8_Change()
set_counter
End Sub
Private Sub set_counter()
Dim x As Integer, counter As Integer
Me.TextBox1.Value = ""
counter = 0
For x = 1 To 8 Step 2
If Me.Controls("OptionButton" & x).Value = True Then counter = counter + 1
Next x
Me.TextBox1.Value = Choose(counter, "D", "C", "B", "A")
End Sub
Private Sub UserForm_Activate()
Me.TextBox1.Value = ""
End Sub
Private Sub UserForm_Click()
Dim x As Integer
Me.TextBox1.Value = ""
For x = 1 To 8
Me.Controls("OptionButton" & x).Value = False
Next x
End Sub
currently i am programming a excel macro. The macro shows a Userform.
In the Userform the User can Select something. After the User has selected something i call Userform.Hide to Hide the Userform and to read the Selection from the Form. After the selection was read i call Unload Userform. Now the Code interacts with the selection. I want to do this in a loop but when the Code trys to show the Userform the second time. I get a exception that the Form is already displayed. I cant understand it, because i called Unload Userform. When i do it in debug mode everthing works as it should.
Userform Code
Private Sub Image1_Click()
SelectCard 1
End Sub
Private Sub Image2_Click()
SelectCard 2
End Sub
Private Sub SelectCard(number As Integer)
SelectedNumber = number
Me.Hide
End Sub
Public Sub CardSelector_Activate(Cards As Cards)
Dim c As card
For Each Key In Cards.CardDictionary.Keys
Set c = Cards.CardDictionary.Items(Key - 1)
If c.value = 1 And c.played Then
Image1.Enabled = False
End If
If c.value = 2 And c.played Then
Image2.Enabled = False
End If
Next Key
number = SelectedNumber
CardSelector.Show
End Sub
Code in the ClassModule i call this in a loop
Sub Costum(Spalte As Integer, Zeile As Integer, SpalteBeginn As Integer, Cards As Cards, CardsOpponent As Cards)
CardSelector.CardSelector_Activate Cards
Dim c As card
Dim number As Integer
number = CardSelector.SelectedNumber
Set c = Cards.CardDictionary.Items(CardSelector.SelectedNumber - 1)
SetCardAsPlaced c, Zeile, Spalte, SpalteBeginn
Unload CardSelector
End Sub
Can someone help me here ?
I am not sure if I fully understand your issue, but this is how I invoke a form using VBA. This is assuming you have a Cancel and OK button:
In the form:
Option Explicit
Private m_ResultCode As VbMsgBoxResult
Private Sub btnCancel_Click()
Call CloseWithResult(vbCancel)
End Sub
Private Sub btnOK_Click()
' Store form control values to member variables here. Then ...
Call CloseWithResult(vbOK)
End Sub
Private Sub CloseWithResult(Value As VbMsgBoxResult)
m_ResultCode = Value
Me.Hide
End Sub
Public Function ShowMe(Optional bNewLayerOptions As Boolean = True) As VbMsgBoxResult
' Set Default to Cancel
m_ResultCode = vbCancel
' Execution will pause here until the form is Closed or Unloaded
Call Me.Show(vbModal)
' Return Result
ShowMe = m_ResultCode
End Function
Then, to call it (please note that frmLayers is my own VBA form object - you would use yours):
Dim dlgLayers As New frmLayers
If (dlgLayers.ShowMe(False) = vbOK) Then
' Proceeed
End If
Does this help you with your issue? I am sorry if I have misunderstood, and I will remove my answer if needed.
Things like xxxxx_Activate etc. are event handlers called by the framework. So, for example, there is an event for activate and an event for initialize. You don't normally have to directly call these yourself if you set your code up correctly. See https://support.microsoft.com/en-us/kb/138819.
I want to show a message 20 seconds after opening the Excel workbook. Code is:
//ThisWorkbook
Private Sub Workbook_Open()
SetTimer
End Sub
//Module1
Public Sub SetTimer()
Application.OnTime Now + TimeValue("00:00:20"), "ShowMsg"
End Sub
Public Sub ShowMsg()
MsgBox ("my message")
End Sub
As you see, code is very simple and it works when user don't update sheet or when they leave updated/focused cell. However, if cursor remains at cell the message will never be shown. It seams that control doesn't return to VBA code while a cell has focus or is updating. Any idea for this issue? Thanks
Here's a workaround:
Sub main()
Dim start As Single
start = Timer
Do
DoEvents
Loop Until Timer > (start + 20) '20 seconds
MsgBox "hello"
End Sub
Edit. Code for further question:
In a module called Module1, enter the following code:
Public start As Single
Sub main2()
start = Timer
Do
DoEvents
Loop Until Timer > (start + 20) '20 seconds
MsgBox "hello"
End Sub
In your ThisWorkbook object (double click on ThisWorkbook from the list of objects in the Project Explorer) enter the following code:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Module1.start = Module1.start + 5
End Sub
Every time any cell in any worksheet in the workbook is changed, another five seconds is added to the timer.
I have a textbox on a userform. It is the only textbox on the form. There are three labels and two buttons in addition to this textbox. Basically, I want the focus to remain on this textbox under all scenarios, other than the moment that one of the buttons would be clicked, but then I want the focus to come right back to the text box. Both buttons have "TakeFocusOnClick" and "TabStop" set to False. I was having problems with getting the focus set to the textbox, which is why I changed these two settings.
Once I changed these settings, the Enter key in the textbox stopped having any effect. I have events written for _AfterUpdate and _KeyPress for the textbox, but they don't fire. As you can see in the code, I have commented out the lines to set the focus to this textbox. Since it is now the only object that can take focus, these lines are not needed (theoretically). When I allowed the other objects to take focus, these lines weren't having any effect (focus was switching to the buttons despite these SetFocus lines).
Here is the code. It is very simple, except that the Enter key isn't triggering the event. Can anyone see why? Thanks.
Private Sub btnDone_Click()
Application.Calculation = xlCalculationAutomatic
formMath.Hide
'Clear statistics
Range("attempts").Value = 0
Range("correct").Value = 0
Sheet5.Range("A2:W500").ClearContents
End Sub
Private Sub btnSubmit_Click()
recordAnswer
'formMath.txtAnswer.SetFocus
End Sub
Private Sub txtAnswer_AfterUpdate()
recordAnswer
'formMath.txtAnswer.SetFocus
End Sub
Private Sub txtAnswer_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If KeyAscii = 13 Then
recordAnswer
End If
End Sub
Private Sub UserForm_Initialize()
'Initialize manual calculation
Application.Calculation = xlCalculationManual
Application.Calculate
'Initialize statistics
Range("attempts").Value = 0
Range("correct").Value = 0
Sheet5.Range("A2:W500").ClearContents
'Initialize first problem
newProblem
End Sub
Sub recordAnswer()
'Update statistics
Dim attempts, correct As Integer
attempts = Range("attempts").Value
correct = Range("correct").Value
Range("results").Offset(attempts, 0).Value = attempts + 1
Range("results").Offset(attempts, 1).Value = lblTopNum.Caption
Range("results").Offset(attempts, 2).Value = lblBotNum.Caption
Range("results").Offset(attempts, 3).Value = lblBop.Caption
Range("results").Offset(attempts, 4).Value = Range("Answer").Value
Range("results").Offset(attempts, 5).Value = txtAnswer.Text
If (Range("Answer").Value = txtAnswer.Text) Then
Range("results").Offset(attempts, 6).Value = 1
Else
Range("results").Offset(attempts, 6).Value = 0
End If
'Update attempts and success
Range("attempts").Value = attempts + 1
Range("correct").Value = correct + 1
newProblem
End Sub
Sub newProblem()
Application.Calculate
formMath.lblTopNum.Caption = Range("TopNum").Value
formMath.lblBotNum.Caption = Range("BotNum").Value
formMath.lblBop.Caption = Range("ProbType").Value
formMath.txtAnswer.Value = ""
'formMath.txtAnswer.SetFocus
End Sub
To start off
You can either in the design mode, set the TabIndex property of the Textbox to 0 or you can set the focus on the textbox in the UserForm_Initialize()
Private Sub UserForm_Initialize()
TextBox1.SetFocus
End Sub
Similarly after any operation that you perform, simply call the TextBox1.SetFocus to revert to the textbox.
Option Explicit
Private Sub UserForm_Initialize()
TextBox1.SetFocus
End Sub
Private Sub CommandButton1_Click()
MsgBox "Hello from Button 1"
TextBox1.SetFocus
End Sub
Private Sub CommandButton2_Click()
MsgBox "Hello from Button 2"
TextBox1.SetFocus
End Sub
Let me know if this is not what you want?
I found a way to accomplish this. In the code above I took out the _KeyPress and _AfterUpdate events and replaced them with:
Private Sub txtAnswer_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case 13: recordAnswer
End Select
End Sub
Not sure why the other methods didn't work, but this does.
Also not sure why simply setting the focus directly didn't work. I suspect that the focus was being set, but then something else was happening subsequently that was changing the focus off of the textbox. Just a guess.
Thanks for the help. I appreciate it.