So, I'm kind of an amateur at VBA.
I'm doing an userform for many users to use at my company.
I need the user to pick a Date.
First, I tried with DTPicker, but that didn't work on the other computer I tried, so my collegue suggested I used a MonthView instead.
I put it in the form, dropping it from the Toolbox, and used this simple code:
Private Sub UserForm_Initialize()
MonthView1.Value = Date
End Sub
Private Sub cmdClose_Click()
Unload Me
End Sub
Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
On Error Resume Next
Dim cell As Object
For Each cell In Selection.Cells
cell.Value = DateClicked
Next cell
Unload Me
End Sub
Worked perfectly.
Then I tried to open the file in another computer and got the 'some objects are not available, blah blah' message. The calendar didn't show up even though I tried registering the OCX file and stuff, and I even could put a new MonthView calendar in the form, but the "existing" one didn't load.
Sooo, I tried adding the object with code, to try and avoid this, I used this code:
Private Sub UserForm_Initialize()
Dim PruebaCal As Object
Set PruebaCal = Controls.Add("MSComCtl2.MonthView.2", "PruebaCal")
PruebaCal.Value = Date
End Sub
Private Sub cmdClose_Click()
Unload Me
End Sub
Private Sub PruebaCal_DateClick(ByVal DateClicked As Date)
On Error Resume Next
Dim cell As Object
For Each cell In Selection.Cells
cell.Value = DateClicked
Next cell
Unload Me
End Sub
This worked for the 'some objects are not available' problem, it loaded perfectly in both computers, but the Click event is not working and I have no idea how to fix that, maybe when adding controls with code the triggering events are different? I don't know.
Related
I have been wondering about this one for a while now.
Let's say I have a formula in A1, Worksheet("Main")
=IF(B2="English";"Good morning";"Guten Morgan")
Then I have userform with code:
Private Sub TextBox1_Change()
ThisWorkbook.Worksheets("Main").Range("A1").Value = Me.TextBox1.Text
End Sub
Private Sub UserForm_Initialize()
Me.TextBox1.Text = ThisWorkbook.Worksheets("Main").Range("A1").Value
End Sub
How can I make it work so, that if I don't input anything into textbox, it will keep displaying functions result. If I will start to type text into textbox it will input my typed text to A1. Now if I open the userform it will overwrite A1 with the text in textbox and there will be no formula anymore. So if I change language in B2 result will no longer be interfaced into textbox.
Can be also some other approach with VBA. Everything is acceptable as long as logic will work.
I have tried to use textbox properly, something like linkedsource or similar, but it is crashing excel workbook sometimes. That's why I am trying to avoid it.
EDIT:
Thank you for suggestions! I have tried to implement this somehow but still don't get it. I am creating variable where I want to store result from ThisWorkbook.Worksheets("Other Data").Range("L49").Value then I would like to use it in Userform Me.TextBox14.Text to be displayed. Then once it is changed in Me.TextBox14.Text and Enter button has been pressed it should change also in ThisWorkbook.Worksheets("Other Data").Range("L49").Value.
Here is my current code I am trying to play with:
Private ProjectClass As String
Private Sub TextBox14_Enter()
ThisWorkbook.Worksheets("Other Data").Range("L49").Value = ProjectClass
End Sub
Private Sub UserForm_Initialize()
Me.TextBox14.Text = ProjectClass
End Sub
The TextBox.Enter event isn't fired when the user presses Enter, but when the control is entered - that is, when it gets the focus and a caret/cursor starts blinking inside it. You'll want to update the backing variable when the value is modified:
Private Sub TextBox14_Enter()
'runs when the control gets focus
End Sub
Private Sub TextBox14_Exit()
'runs when the control loses focus
End Sub
Private Sub TextBox14_Change()
'runs whenever the value changes (real-time)
End Sub
So in this case I'd go with the TextBox.Change event handler, and make it update the variable (not the worksheet):
Private ProjectClass As String
Private Sub TextBox14_Change()
ProjectClass = TextBox14.Text
End Sub
Now the problem is that the ProjectClass value needs to be accessible from outside the form, so that the caller can set an initial value. One way to do this could be to expose it as a property - one property (get+let) for each field you want to seed a value for:
Public Property Get ProjClass() As String
ProjClass = ProjectClass
End Property
Public Property Let ProjClass(ByVal value As String)
ProjectClass = value
ApplyModelProperties
End Property
Private Sub ApplyModelProperties()
TextBox14.Text = ProjectClass
'...
End Sub
Now from outside the form, at the call site (the code that's showing this dialog), you can seed the value from the worksheet, and the form never needs to know or care that a worksheet was involved:
With New UserForm1
.ProjClass = ThisWorkbook.Worksheets("Other Data").Range("L49").Value
.Show
MsgBox .ProjClass
End With
Note that because the value is exposed as a property, the calling code doesn't need to know about TextBox14 anymore.
When the column is refreshing nothing is happening but when I go to the cell and change the value then it is changing.
I want when cells update through refresh it should run.
The column updates but the code doesn't trigger the macro.
Also tried Worksheet_Calculate().
The column is linked with online stock data from NSE website.
Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("B:B")) Is Nothing Then
MsgBox "Cell Value Changed"
Call MyMacro()
End If
End Sub
On internet just told to use Worksheet_Calculate().
Also if trying to update the cell which is equal to a cell in Range("B:B"), the value changes but macro doesn't trigger.
Maybe give this a try by using Workbook_SheetChange instead of Worksheet_Change
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("B:B")) Is Nothing Then
MsgBox "Cell Value Changed"
Call MyMacro()
End If
End Sub
Note that you need to put your code in ThisWorkbook and not your module
Edit : to test the Answer :
Sub TryMe()
For i = 1 To 100
Cells(2, 2).Value = i
Next
End Sub
TryMe Should be added inside a module like below
Workbook_SheetChange hould be added inside ThisWorkbook like below
When we execute test module we should have stuff like this:
and so on..
EDIT 2 If Value are changed by formula :
Give this a try :
This code should be placed in the sheet you are using (in my exemple Sheet1)
Private Sub Worksheet_Calculate()
Dim rng As Range
Set rng = Range("B:B")
If Not Intersect(rng, Range("B:B")) Is Nothing Then
MsgBox "Cell Value Changed"
End If
End Sub
In a Module execute this code once :
Sub TryMe()
ActiveWorkbook.RefreshAll
Application.Calculation = xlAutomatic
End Sub
then this should work
You can use events of QueryTable object behind the table linked to a web source. To do that, you first need to create a class module. Let's call it clsQryTebleEvents. In that module place a WithEvents variable of type Excel.QueryTable and set it to the QueryTable for which you want to capture events. Here's the code for clsQryTableEvents:
Option Explicit
Private WithEvents qryTable As Excel.QueryTable
Private Sub Class_Initialize()
'QueryTable connected to a webpage is on Sheet1, and it's the only table on that sheet, so we can access it with ListObjects(1)
Set qryTable = Sheet1.ListObjects(1).QueryTable
End Sub
Private Sub Class_Terminate()
'Free Memory
Set qryTable = Nothing
End Sub
'You can use other events as well
Private Sub qryTable_BeforeRefresh(Cancel As Boolean)
MsgBox "Refresh is about to start!", vbInformation
End Sub
Next, you need to initialize a variable of this class. You can declare a Public variable inside a standard module and the use Workbook_Open event to instantiate it. Code in a standard module:
Option Explicit
Public objQryTable As clsQryTableEvents
Code in ThisWorkbook:
Option Explicit
Private Sub Workbook_Open()
Set objQryTable = New clsQryTableEvents
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
'Free memory
Set objQryTable = Nothing
End Sub
All done! Next time you open the workbook, the objQryTable will be initialised and will start listening to refresh events.
Hi I am trying to use a publicly declared variable that has a value assigned to it upon clicking one of two optionbuttons inside a userform.
The userform does show and I can click either of the two buttons i have in the frame I created, but the variable does not pick up the click or actually I don't know what I'm doing with the userform controls. And i don't think the form hides either, clicking the optionbutton seems to be a dummy click, it highlights but does nothing after that.
Plus i'm not sure if the code itself needs to be placed on the userform' code section or the module code section, does it make a difference? Currently running it on the module code section.
Option Explicit
Dim C As String
Public Sub OptionButton1_Click()
C = "Delivery"
End Sub
Public Sub OptionButton2_Click()
C = "Holiday"
End Sub
Public Sub Optionbutton()
Userform1.Show
Sheet1.Cells(1, 1).Value = C
Userform1.Hide
End Sub
********--Edit-*********
I guess Zack's method gets the job done, printing to Cell A1, but what I was really after is although the event handler needs to be private, running debug points out that the execution stops when the private sub ends, which could be optionbutton1 or optionbutton2's click event, which is what led me to believe the click was a dummy click.
But what I was really after is for the C variable to be available in the public sub that I execute from, is there a way for the execution to divert to the public sub after the C is assigned a value in the optionbutton private sub?
For example if the C was assigned in the private sub but my success criteria were defined by the successful execution of the public Sub defined above, because i have a larger macro where that variable will be used inside the public sub, and this is only part of the problem, or the problem I can't solve.
If I understand correctly, your form has two option buttons. Thus, your form's code-behind should look like this:
Option Explicit
Private Sub OptionButton1_Click()
C = "Delivery"
End Sub
Private Sub OptionButton2_Click()
C = "Holiday"
End Sub
This assumes there's a global variable C declared somewhere, in a standard module:
Option Explicit
Public C As String
Public Sub Optionbutton()
Userform1.Show
Sheet1.Cells(1, 1).Value = C
End Sub
Note that this displays the form modally, which means the next instruction only runs after the form is closed/destroyed. For that reason, there's no need for the subsequent Userform1.Hide call: the form is already gone by then.
Once you're comfortable with manipulating global variables from a form's code-behind, read UserForm1.Show (I wrote that article) for insight on a vastly more robust way to go about this.
Try this:
You will need to tell the control where to place the value after the button is clicked.
Option Explicit
Dim C As String
Private Sub OptionButton1_Click()
C = "Delivery"
Sheet1.Cells(1, 1) = C
Userform1.Hide
End Sub
Private Sub OptionButton2_Click()
C = "Holiday"
Sheet1.Cells(1, 1) = C
Userform1.Hide
End Sub
Public Sub Optionbutton()
Userform1.Show vbModeless
If cells G8 or A11:A29 are clicked, I want a pop up calendar to pop up and place the date within that/those selected cell(s). We will want to use the pop up calendar on other files and other users' PCs, though the files will vary in where we want the cells to display the pop up calendar. Would an add in be used for this or can I simply figure out the code and include it in other workbooks? I had five users counting myself that could run my new file without issue but there are at least three users who get a "Could not load an object because it is not available on this machine" error message when clicking within the specified cells. Some of the links I used: Extend Office VBA Express Font Stuff
Code In sheet 1:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
On Error Resume Next
If Not Intersect(Target, Range("A11:A29")) Is Nothing Then frmCalendar.Show
If Not Intersect(Target, Range("G8")) Is Nothing Then frmCalendar.Show
End Sub
Code in Module 1: (Not even sure I need this. I think this was originally because I had buttons)
Sub OpenCalendar()
frmCalendar.Show
End Sub
Code in frmCalendar:
Private Sub cmdClose_Click()
Unload Me
End Sub
Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
On Error Resume Next
Dim xRg As Object
For Each xRg In Selection.Cells
xRg.Value = DateClicked
Next xRg
Unload Me
End Sub
Private Sub UserForm_Initialize()
If IsDate(ActiveCell.Value) Then
Me.MonthView1.Value = ActiveCell.Value
End If
End Sub
I truly appreciate any and all help or point in the right direction! Cheers!
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.