I have the following code that works as expected:
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
Dim cmdBtn As CommandBarButton
Dim currentUPC As String
Dim currentArticle As String
Set cmdBtn = Application.CommandBars("Cell").FindControl(, , "testBt")
If Intersect(Target, Range("C21:C42")) Is Nothing Then
If Not cmdBtn Is Nothing Then cmdBtn.Delete
Exit Sub
End If
If Not cmdBtn Is Nothing Then Exit Sub
Set cmdBtn = Application.CommandBars("Cell").Controls.Add(Temporary:=True)
currentUPC = ActiveCell.Value
currentArticle = ActiveCell.Offset(0, 1).Value
With cmdBtn
.Tag = "testBt"
.Caption = "Goto UPC"
.Style = msoButtonCaption
.OnAction = "=gotoUPC(" & currentUPC & ")"
End With
End Sub
But the macro it runs is not quite working as planned:
Sub gotoUPC(currentUPC As String)
Sheets("UPC Summary").Range("A21").Value = currentUPC
Worksheets("UPC Summary").Activate
End Sub
The value in Range A21 updates correctly but it will not activate the worksheet as required.
Any additional thoughts on my method of passing the parameter appreciated #FaneDuru
Any thoughts appreciated, many thanks, Alan.
If you want to go to the worksheet 'UPC Summary' you could use this.
Application.Goto Sheets("UPC Summary").Range("A1"), True
Related
I made a workbook that has a userform thar is used to fill information in a new row, the information in the textboxes should be prefilled by using the information on the row below. This has to be repeated as many times as an input box value.
So far so good, but now I also need the users to be able to view other sheets in the same workbook where the required information is stored while the userform is open.
if I show the userform modeless I can view other sheets but then the code just keeps going and the second time the userform should pop up it doesn't.
I found a solution to that: using DoEvent.
but now the information is not (pre)filled correctly
Private Sub CommandButton2_Click()
Dim myValue As String
myValue = InputBox("How many do you have?")
If StrPtr(myValue) = 0 Then Exit Sub
For i = 1 To myValue
Range("A4").EntireRow.Insert
UserForm1.Show vbModeless
Do While UserForm1.Visible
DoEvents
Loop
Next
End Sub
What happens now is that the information from a row below is used regardless of any changes made by the user.
Does anyone have a solution?
Edit:
I don't think it is immediately required to understand my question but it might help a bit..
The rest of the code from the userform is as follows
Private Sub CommandButton1_Click()
Unload UserForm1
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
Cancel = True
Range("A4").EntireRow.delete
End
End If
End Sub
Private Sub TextBox1_Change()
Dim myValue As Variant
myValue = TextBox1
Range("A4").Value = myValue
End Sub
Private Sub UserForm_Initialize()
Me.TextBox1.Value = Format(Range("A2"), "dd/mm/yyyy")
Me.TextBox2.Value = Range("B5").Value
Me.TextBox3.Value = Range("C5").Value
Me.TextBox4.Value = Range("D5").Value
Me.TextBox5.Value = Range("E5").Value
Me.TextBox6.Value = Range("F5").Value
Me.TextBox7.Value = Range("G5").Value
Me.TextBox8.Value = Range("H5").Value
Me.TextBox9.Value = Range("J5").Value
Me.TextBox10.Value = Range("K5").Value
End Sub
Private Sub TextBox10_Change()
Dim myValue As Variant
myValue = TextBox10
Range("K4").Value = myValue
End Sub
Private Sub TextBox11_Change()
End Sub
Private Sub TextBox2_Change()
Dim myValue As Variant
myValue = TextBox2
Range("B4").Value = myValue
End Sub
Private Sub TextBox3_Change()
Dim myValue As Variant
myValue = TextBox3
Range("C4").Value = myValue
End Sub
Private Sub TextBox4_Change()
Dim myValue As Variant
myValue = TextBox4
Range("D4").Value = myValue
End Sub
Private Sub TextBox5_Change()
Dim myValue As Variant
myValue = TextBox5
Range("E4").Value = myValue
End Sub
Private Sub TextBox6_Change()
Dim myValue As Variant
myValue = TextBox6
Range("F4").Value = myValue
End Sub
Private Sub TextBox7_Change()
Dim myValue As Variant
myValue = TextBox7
Range("G4").Value = myValue
End Sub
Private Sub TextBox8_Change()
Dim myValue As Variant
myValue = TextBox8
Range("H4").Value = myValue
End Sub
Private Sub TextBox9_Change()
Dim myValue As Variant
myValue = TextBox9
Range("J4").Value = myValue
End Sub
~~
I figured that it indeed had to do with the fact that your initial code did not retrigger the TextBox#_Change subs as intended. I did it a little differently, and triggered them in CommandButton2_Click. This way, you don't need to reload really. But whatever works; just sharing for comparison. So, I am assuming a UserForm like this:
We will move row 4 down on Confirm Input. On Cancel, we'll clear it and exit. And on Confirm Input, the user will (continuously) be asked whether he wants to submit another entry. If not, we'll clear row 4 and exit as well.
So, I've rewritten these parts:
Private Sub CommandButton1_Click()
Range("A4").EntireRow.ClearContents
Unload UserForm1
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
Cancel = True
Range("A4").EntireRow.ClearContents
Range("A4").Resize(1, 11).Interior.Color = vbYellow
End
End If
End Sub
Private Sub CommandButton2_Click()
Range("A4").Resize(1, 11).Interior.Color = vbWhite
Range("A4").Resize(1, 11).Insert
Range("A4").Resize(1, 11).Interior.Color = vbYellow
For i = 1 To 10
myValue = Me.Controls("TextBox" & i).Value
Me.Controls("TextBox" & i).Value = ""
Me.Controls("TextBox" & i).Value = myValue
Next i
answer = MsgBox("Do you wish to add another row?", vbYesNo)
If answer = vbYes Then
Else
Range("A4").EntireRow.ClearContents
Unload UserForm1
End If
End Sub
Private Sub TextBox1_Change()
Dim myValue As Variant
myValue = TextBox1
If myValue = "" Then
Range("A4").Value = myValue
Else
Range("A4").Value = CDate(myValue)
End If
End Sub
You might want to get rid of the color (re)setting bits. But it may be good to realize that the practice of inserting rows all the time may have unintended effects for formatting. Suppose, for whatever reason, you want row 6 to have a red background. As is, the code will keep pushing this formatting one row down each time. This may be what you want, of course... Other than that, the "update" for TextBox1_Change makes sure you export an actual Excel Date, not a string.
Final warning (since we're using vbModeless): be aware that (both in your code and mine) there is no reference to the worksheet. Suppose your user goes into another sheet and clicks Confirm Input there, this will trigger Range("A4").Resize(1, 11).Insert inside the wrong sheet! Seems highly advisable to fix this.
I found a way..
I now changed the sub names of the textbox#_change subs and call them all on "userform unload".
Private Sub CommandButton1_Click() ' this is the command button on the userform
Call TX1
Unload UserForm1
End Sub
enter image description hereI have a spreadsheet that has 3 checkbox options for each row, I have created a VBA to disable the other 2 checkboxes once a checkbox is created (so that only 1 checkbox can be checked), however my solution only works for one row and I need some help in rewriting this so that it will apply to all rows please. (I'm new to VBA).
The code I have used is this:
Private Sub CheckBox1_Click()
If CheckBox1.Value = True Then
CheckBox2.Value = False
CheckBox2.Enabled = False
CheckBox3.Value = False
CheckBox3.Enabled = False
Else
CheckBox2.Value = False
CheckBox2.Enabled = True
CheckBox3.Value = False
CheckBox3.Enabled = True
End If
End Sub
Private Sub CheckBox2_Click()
If CheckBox2.Value = True Then
CheckBox1.Value = False
CheckBox1.Enabled = False
CheckBox3.Value = False
CheckBox3.Enabled = False
Else
CheckBox1.Value = False
CheckBox1.Enabled = True
CheckBox3.Value = False
CheckBox3.Enabled = True
End If
End Sub
Private Sub CheckBox3_Click()
If CheckBox3.Value = True Then
CheckBox1.Value = False
CheckBox1.Enabled = False
CheckBox2.Value = False
CheckBox2.Enabled = False
Else
CheckBox1.Value = False
CheckBox1.Enabled = True
CheckBox2.Value = False
CheckBox2.Enabled = True
End If
End Sub
You should probably just use Radios it would be a lot simpler.
If you are intent on doing this you will need to delete all your boxes and then put this code in. It will create and name your boxes and assign them code on click.
Alright, This needs to go in your Sheet module:
Sub Worksheet_Activate()
'Change Module2 to whatever the module name you are using is.
Module2.ActivateCheckBoxes ActiveSheet
End Sub
This next stuff will go into the module you're referencing from the Worksheet Module.
Sub ActivateCheckBoxes(sht As Worksheet)
If sht.CheckBoxes.Count = 0 Then
CreateCheckBoxes sht
End If
Dim cb As CheckBox
For Each cb In sht.CheckBoxes
'You may be able to pass sht as an object, It was giving me grief though
cb.OnAction = "'Module2.CheckBoxClick """ & cb.name & """, """ & sht.name & """'"
Next cb
End Sub
Sub CreateCheckBoxes(sht As Worksheet)
Dim cell As Range
Dim chkbox As CheckBox
With sht
Dim i As Long
Dim prevrow As Long
prevrow = 0
For Each cell In .Range("B2:D5") 'Change this to whatever range you want.
If prevrow < cell.row Then
prevrow = cell.row
i = 0
End If
Set chkbox = .CheckBoxes.Add(cell.Left, cell.Top, 30, 6)
With chkbox
.name = "CheckBox" & i & "_" & cell.row
.Caption = ""
End With
i = i + 1
Next cell
End With
End Sub
Sub CheckBoxClick(chkname As String, sht As String)
Dim cb As CheckBox
With Worksheets(sht)
For Each cb In .CheckBoxes
If Split(cb.name, "_")(1) Like Split(chkname, "_")(1) And Not cb.name Like chkname Then
cb.Value = -4146
End If
Next cb
End With
End Sub
You do not say anything about your sheet check boxes type... Please, test the next solution. It will be able to deal with both sheet check boxes type:
Copy this two Subs in a standard module:
Public Sub CheckUnCheckRow(Optional strName As String)
Dim sh As Worksheet, s As CheckBox, chK As OLEObject ' MSForms.CheckBox
Set sh = ActiveSheet
If strName <> "" Then
Set chK = sh.OLEObjects(strName) '.OLEFormat.Object
solveCheckRow chK.Object.Value, sh, Nothing, chK
Else
Set s = sh.CheckBoxes(Application.Caller)
solveCheckRow s.Value, sh, s
End If
End Sub
Sub solveCheckRow(boolVal As Long, sh As Worksheet, chF As CheckBox, Optional chK As OLEObject)
Dim s As CheckBox, oObj As OLEObject, iCount As Long
If Not chF Is Nothing Then
For Each s In sh.CheckBoxes
If chF.TopLeftCell.Address <> s.TopLeftCell.Address Then
If s.TopLeftCell.Row = chF.TopLeftCell.Row Then
s.Value = IIf(boolVal = -4146, 1, -4146): iCount = iCount + 1
If iCount = 2 Then Exit Sub
End If
End If
Next
ElseIf Not chK Is Nothing Then
For Each oObj In sh.OLEObjects
If oObj.TopLeftCell.Address <> chK.TopLeftCell.Address Then
If oObj.TopLeftCell.Row = chK.TopLeftCell.Row Then
boolStopEvents = True
oObj.Object.Value = IIf(boolVal = 0, True, False): iCount = iCount + 1
boolStopEvents = False
If iCount = 2 Then Exit Sub
End If
End If
Next
End If
End Sub
For case of Form check boxes type:
a). Manually assign the first sub to all your Form Type check boxes (right click - Assign Macro, choose CheckUnCheckRow and press OK).
b). Automatically assign the macro:
Dim sh As Worksheet, s As CheckBox
Set sh = ActiveSheet ' use here your sheet keeping the check boxes
For Each s In sh.CheckBoxes
s.OnAction = "'" & ThisWorkbook.Name & "'!CheckUnCheckRow"
Next
End Sub
If your check boxes have already assigned a macro, adapt CheckUnCheckRow, in Form check boxes section, to also call that macro...
For case of ActiveX check boxes:
a). Create a Public variable on top of a standard module (in the declarations area):
Public boolStopEvents
b). Manually adapt all your ActiveX check boxes Click or Change event, like in the next example:
Private Sub CheckBox1_Click()
If Not boolStopEvents Then CheckUnCheckRow "CheckBox1"
End Sub
Private Sub CheckBox2_Click()
If Not boolStopEvents Then CheckUnCheckRow "CheckBox2"
End Sub
Private Sub CheckBox3_Click()
If Not boolStopEvents Then CheckUnCheckRow "CheckBox3"
End Sub
and so on...
c). Or do all that with a click, using the next piece of code:
Sub createEventsAllActiveXCB()
Dim sh As Worksheet, oObj As OLEObject, strCode As String, ButName As String
Set sh = ActiveSheet 'use here your sheet keeping ActveX check boxes
For Each oObj In sh.OLEObjects
If TypeName(oObj.Object) = "CheckBox" Then
ButName = oObj.Name
strCode = "Private Sub " & ButName & "_Click()" & vbCrLf & _
" If Not boolStopEvents Then CheckUnCheckRow """ & ButName & """" & vbCrLf & _
"End Sub"
addClickEventsActiveXChkB sh, strCode
End If
Next
End Sub
Anyhow, the code cam be simplified in order to deal with only a type of such check boxes. If you intend to use it and looks too bushy, I can adapt it only for the type you like. Like it is, the code deals with both check box types, if both exist on the sheet...
Save the workbook and start playing with the check boxes. But, when you talk about check boxes on a row, all tree of them must have the same TopLeftCell.Row...
I would like to generate some code that allows an end user to select one of many charts from a sheet, after which I will do a bunch of manipulation based on that selection.
I am looking for something similar to the Application.Inputbox Type:=8 that allows for an object selection instead of a range selection.
Am I asking to much of humble old VBA??
It's a lot easier to select the chart first, then run code on the selected chart(s), than it is to pause the code and try to select the chart(s) from within the code.
But it can be done.
You need a userform, called F_ChartChooser with two buttons, btnCancel and btnContinue.
The code in the F_ChartChooser module:
Option Explicit
Private Sub btnCancel_Click()
CancelProcedure
End Sub
Private Sub btnContinue_Click()
ContinueProcedure
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
' so clicking red X doesn't crash
If CloseMode = 0 Then
Cancel = True
CancelProcedure
End If
End Sub
The code in the regular module consists of a main procedure which must get the chart(s) from the user. It has to call the userform modelessly so the user can select charts in the worksheet. This means the code continues running while the form is displayed, so the thing to do is end the sub when the userform is called.
Based on what happens with the userform, the code either continues with CancelProcedure or with ContinueProcedure. Here's the code:
Option Explicit
Dim mfrmChartChooser As F_ChartChooser
Sub Main()
' code here
' need to select chart(s) here
Application.Goto ActiveCell
Set mfrmChartChooser = New F_ChartChooser
mfrmChartChooser.Show vbModeless
End Sub
Sub CancelProcedure()
Unload mfrmChartChooser
Set mfrmChartChooser = Nothing
MsgBox "User canceled.", vbExclamation
End Sub
Sub ContinueProcedure()
Unload mfrmChartChooser
Set mfrmChartChooser = Nothing
If Not ActiveChart Is Nothing Then
' do something with active chart
' this demo is announcing that it was selected
MsgBox """" & ActiveChart.ChartTitle.Text & """ was selected.", vbExclamation
' end of demo code
ElseIf TypeName(Selection) = "DrawingObjects" Then
Dim sh As Shape
Dim vCharts As Variant
Dim nChart As Long
ReDim vCharts(0 To nChart)
For Each sh In Selection.ShapeRange
If sh.HasChart Then
' do something here with each chart
' this demo is building a list of selected charts
nChart = nChart + 1
ReDim Preserve vCharts(0 To nChart)
vCharts(nChart) = sh.Chart.ChartTitle.Text
' end of demo code
End If
Next
' this demo now is showing the list of selected charts
If nChart = 0 Then
MsgBox "No chart selected.", vbExclamation
Else
If nChart = 1 Then
MsgBox """" & vCharts(nChart) & """ was selected.", vbExclamation
Else
Dim sPrompt As String
sPrompt = nChart & " charts selected:" & vbNewLine & vbNewLine
Dim iChart As Long
For iChart = 1 To nChart
sPrompt = sPrompt & """" & vCharts(iChart) & """" & IIf(iChart < nChart, vbNewLine, "")
Next
MsgBox sPrompt, vbExclamation
End If
End If
' end of demo code
Else
' do nothing because no chart was selected
' this demo is announcing that nothing was selected
MsgBox "No chart selected.", vbExclamation
' end of demo code
End If
End Sub
The CancelProcedure and ContinueProcedure routines above have excess code in them just to help with the demo. In real code I would streamline them like this, probably not even bother to notify the user when nothing was selected (they know they canceled, right?), and just process the selected chart(s):
Sub CancelProcedure()
Unload mfrmChartChooser
Set mfrmChartChooser = Nothing
End Sub
Sub ContinueProcedure()
Unload mfrmChartChooser
Set mfrmChartChooser = Nothing
If Not ActiveChart Is Nothing Then
' do something with active chart
ProcessChart ActiveChart
ElseIf TypeName(Selection) = "DrawingObjects" Then
Dim sh As Shape
Dim vCharts As Variant
Dim nChart As Long
ReDim vCharts(0 To nChart)
For Each sh In Selection.ShapeRange
If sh.HasChart Then
' do something here with each chart
ProcessChart sh.Chart
Next
End Sub
I would like to achieve the following:
In my excel sheet I have a set of data to which I've applied dynamic filtering by creating a "Search box".
The filtering itself works okay, no problems there, however, I would like to further improve it, by highlighting the text (that is entered into the search box) in the filtered rows in red.
I am attaching a screenshot of what I would like to see in the final version.
Any idea how this can be entered into my current code?
As always, any help is greatly appreciated!
Thank you!
Below is the code I use for the dynamic filtering:
Private Sub TextBox1_Change()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
If Len(TextBox1.Value) = 0 Then
Sheet1.AutoFilterMode = False
Else
If Sheet1.AutoFilterMode = True Then
Sheet1.AutoFilterMode = False
End If
Sheet1.Range("B4:C" & Rows.Count).AutoFilter field:=1, Criteria1:="*" & TextBox1.Value & "*"
End If
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Consider something like this - Write in a worksheet the following:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Count > 1 Then Exit Sub
If Target <> Range("a1") Then Exit Sub
SelectAndChange (Target)
End Sub
Private Sub SelectAndChange(strValue As String)
Dim rngCell As Range
Dim rngRange As Range
Dim strLookFor As String
Dim arrChar As Variant
Dim lngCounter As Long
If strValue = vbNullString Then Exit Sub
Application.EnableEvents = False
Set rngRange = Range("E1:E10")
rngRange.Font.Color = vbBlack
strLookFor = Range("A1").Value
For Each rngCell In rngRange
For lngCounter = 1 To Len(rngCell) - Len(strLookFor) + 1
If Mid(rngCell, lngCounter, Len(strLookFor)) = strLookFor Then
rngCell.Characters(lngCounter, Len(strLookFor)).Font.Color = vbRed
End If
Next lngCounter
Next rngCell
Application.EnableEvents = True
End Sub
The values in E1:E10 would be dependent from the value in A1 like this:
Employee Login System using Excel with Macro.
I'm using a very simple technique of "if elseif then"
I want to display Employee Name when their ID is typed.
I used very simple code:
Dim CM As Boolean
Dim UserRange As Range
Dim x As Range
'EASY
Private Sub cmdClear_Click()
txtEmpID.Value = ""
txtName.Value = ""
txtEmpID.SetFocus
End Sub
Private Sub cmdLogin_Click()
End Sub
Private Sub txtEmpID_Change()
'If txtEmpID.Value = "111" Then
'txtName.Value = "Ryan"
'
'ElseIf txtEmpID.Value = "222" Then
'txtName.Value = "Tim"
'
'End If
End Sub
Private Sub UserForm_activate()
Do
If CM = True Then Exit Sub
TextBox1 = Format(Now, "hh:mm:ss")
DoEvents
Loop
Set UserRange = Sheets("Sheet1").Range("B:B")
For Each x In UserRange.Cells
If x.Value = txtEmpID.Text Then
x.Offset(1, 0) = txtName.Value
End If
Exit For
Next x
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
CM = True
End Sub
However I want to have a sheet that holds Employee Name (column A) and ID(column B) Sheet
Then from there, I can add more employee names and IDs. Also when I click on Login it will display the current time in Column C and then It will also display their time-out. Here's my main form Main Form
Thank you so much.
Not 100% sure I understand but here's my response:
Here's a way to update the field from the worksheet:
Private Sub txtEmpID_Change()
Dim mySheet As Worksheet
Dim myRange As Range
Set mySheet = Sheets("Emp_ID")
Set myRange = mySheet.Range("B:B").Find(txtEmpID.Value, , , xlWhole)
If Not myRange Is Nothing Then
txtName.Value = myRange.Offset(0, -1)
Else
txtName.Value = "Match not found"
End If
End Sub
Set that to occur whenever there's an update.
As for recording the login time: myRange.offset(0,1) = Format(Now,"hh:mm:ss")
How will you know / display the logout time when someone is logging in?