Creating barcodes in Excel - vba

I am using barcode font to generate barcodes,
column A text - *column B Barcode*
I have the following macro in ThisWorkbook which works okay.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If IsEmpty(Target) Or Target.Column <> 1 And Target.Column <> 4 Then Exit Sub
Dim DataRow As Integer
DataRow = Target.Cells.Row
While Not IsEmpty(Cells(DataRow, Target.Column))
Target.Worksheet.Cells(DataRow, Target.Column + 1) = "*" & Target.Worksheet.Cells(DataRow, Target.Column) & "*"
DataRow = DataRow + 1
Wend
End Sub
when I scan 22 digit # in column A; on column B would like to skip the first 7 digit and have the last 15 digit on column B
e.g:
If 22 digit skip first 7
If 32 digit skip first 16 & last 4
If 34 digit skip first 22

First off, the sh parameter of the Workbook_SheetChange event macro is the worksheet object containing Target. You can use it directly; there is no need to pare the worksheet from Target.
Next, it is always a good idea when adding/modifying/deleting objects within a Worksheet_Change or Workbook_SheetChange event macro to turn off application.enableevents so the macro does not try to run on top of itself when it changes/deleted/adds a value on the same (or different) worksheet.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Not Intersect(Sh.Range("A:A, D:D"), Target) Is Nothing Then
On Error GoTo Fìn
Application.EnableEvents = False
Dim DataRow As Long, rng As Range
For Each rng In Intersect(Sh.Range("A:A, D:D"), Target)
Select Case Len(rng.Value2)
Case 0
'do nothing
Case 22
rng.Offset(0, 1) = Chr(42) & Mid(rng.Value2, 8, 99) & Chr(42)
Case 32
rng.Offset(0, 1) = Chr(42) & Mid(rng.Value2, 8, 21) & Chr(42)
Case 34
rng.Offset(0, 1) = Chr(42) & Mid(rng.Value2, 23, 99) & Chr(42)
Case Else
rng.Offset(0, 1) = Chr(42) & rng.Value2 & Chr(42)
End Select
Next rng
End If
Fìn:
Application.EnableEvents = True
End Sub
Target knows which worksheet it is on so there is really no need to define the worksheet when referencing a cell offset to Target.
A Select Case ... End Select` based on the length of the values in Target seemed the best solution and allows for easy expandability.
And finally, do you really need this for multiple worksheets as a Workbook_SheetChange event macro or would a single worksheet's Worksheet_Change suffice?

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim tmp,v
Dim c As Range
On Error Goto haveError
For Each c in Target.Cells
tmp=trim(c.Value)
If Len(tmp) > 0 And (c.Column=1 Or c.Column=4) Then
Select Case Len(tmp)
Case 22: v = Right(tmp, Len(tmp)-7)
Case 32: 'etc
Case 34: 'etc
Case Else: v=""
End Select
If Len(v)>0 Then
Application.EnableEvents = False
c.offset(0,1).value = "*" & v & "*"
Application.EnableEvents = True
End If
End If
Next c
Exit sub
haveError:
Application.EnableEvents = True
End Sub

Related

seeking a solution for when user decrements a cell's value, another cell (different column) will increment that same value

example:
Column A = 1
Column B = 0
[user changes value of Column A to 0]
new values:
Column A = 0
Column B = 1
Here is an example for columns A and B. Insert this event macro in the worksheet code area:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range, OldValue As Variant, NewValue As Variant, Delta As Variant
Set A = Range("A:A")
If Intersect(Target, A) Is Nothing Then Exit Sub
If Target.Count > 1 Then Exit Sub
Application.EnableEvents = False
NewValue = Target.Value
Application.Undo
OldValue = Target.Value 'capture previous value
Target.Value = NewValue 'restore new value
If NewValue < OldValue Then
Delta = OldValue - NewValue
Target.Offset(0, 1).Value = Target.Offset(0, 1).Value + Delta
End If
Application.EnableEvents = True
End Sub
If a value in column A is reduced by user action, the value in column B (in the adjacent cell) will be increased by the same amount.
If the value in column A is increased, then no action is taken. If more than one cell in column A is changed at the same time, no action is taken.
I kind of dislike that you have not showed any effort to solve your question, but given it is a fairly intriguing topic I gave it a go as a form of a nice "practice homework" for myself.
This code produces the expected result:
Dim oldval As Long
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
If Not Intersect(Target, ws.Range("A1:A" & Rows.Count)) Is Nothing Then
If IsNumeric(Target.Value2) Then
oldval = Target.Value2
Else
oldval = 0
End If
End If
End Sub
This first procedure is used to store the original value before change ^
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A1:A" & Rows.Count)) Is Nothing Then
Target.Offset(0, 1).Value2 = oldval - Target.Value2
End If
End Sub
And upon change, displays the difference in column B ^
Input Data:
Upon change in Column A (result as expected)
I have this, that will add sum on column A and B on workbook_open and then use it if A or B changes the value.
This should go to the ThisWorkbook code area:
Private Sub Workbook_Open()
Dim i As Integer
For i = 1 To Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
Sheets("Sheet1").Range("C" & i) = Sheets("Sheet1").Range("A" & i) + Sheets("Sheet1").Range("B" & i)
Next i
End Sub
This should got to the worksheet code area:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 1 Then
Cells(Target.Row, 2) = Cells(Target.Row, 3) - Cells(Target.Row, 1)
End
End If
If Target.Column = 2 Then
Cells(Target.Row, 1) = Cells(Target.Row, 3) - Cells(Target.Row, 2)
End
End If
End Sub

Applying formula with changing row position to VBA

I have a worksheet that count the number of days between a designated date in column A and today() date in column B which stops the counting in column C if there is the word "CLOSED" in Column D. But I have a problem where I want to reapply back the formula if column D is blank again. I'm not sure how to make the column rows appear at the right place for the formula to be used
Below is the VBA code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells = "CLOSED" Then
'Run only when change is made in Column D
If Target.Column = 4 Then
Application.EnableEvents = False
'Replace the formula with the current result
Range("C" & Target.Row) = Range("C" & Target.Row).Value
Range("B" & Target.Row) = Range("B" & Target.Row).Value
Application.EnableEvents = True
End If
End If
If Target.Cells = "" Then
'Run only when change is made in Column D
If Target.Column = 4 Then
Application.EnableEvents = False
'Replace the formula with the current result
Range("C" & Target.Row).Formula = "=TRUNC($B2 - $A2)"
Range("B" & Target.Row).Value = "=Today()"
Application.EnableEvents = True
End If
End If
End Sub
I would really appreciate it if someone can teach me how to properly change the code:
Range("C" & Target.Row).Formula = "=TRUNC($B2 - $A2)"
as I am still new to VBA programming and would like to learn from my mistake
Below will do what you want. Learn that you can use the .FormulaR1C1 similar to effect of filling up/down. The potential issues including more than 1 cells is changed. Have not put checks if the cells in columns A/B are empty.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim oRng As Range
Application.EnableEvents = False
For Each oRng In Target.Cells
With oRng
If .Column = 4 Then
If UCase(Trim(.Value)) = "CLOSED" Then
.Worksheet.Cells(.Row, "B").Value = .Worksheet.Cells(.Row, "B").Value
.Worksheet.Cells(.Row, "C").Value = .Worksheet.Cells(.Row, "C").Value
ElseIf Len(Trim(.Value)) = 0 Then
.Worksheet.Cells(.Row, "B").Formula = "=Today()"
.Worksheet.Cells(.Row, "C").FormulaR1C1 = "=TRUNC(RC[-2]-RC[-3])"
End If
End If
End With
Next oRng
Application.EnableEvents = True
End Sub
My understanding is that:
you need to act for any column 4 cell change, only
there can be more than one changed cell in column 4
so I'd go like follows (explanations in comments):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rangeToProcess As Range
Set rangeToProcess = Intersect(Target, Columns(4)) 'mind edited cells in column 4 only
If rangeToProcess Is Nothing Then Exit Sub
Dim cell As Range
Application.EnableEvents = False
For Each cell In rangeToProcess 'loop through edited cells in column 4
With cell.Offset(, -2).Resize(, 2) ' reference a 2-cells range at the left of current cell
Select Case cell.Value 'process current cell value
Case "CLOSED" ' if it's "CLOSED" ...
.Value = .Value ' ... then leave values in referenced cells
Case "" ' if it's "" ...
.FormulaR1C1 = Array("=Today()", "=TRUNC(RC[-1]-RC[-2])") ' ... then restore formulas
End Select
End With
Next
Application.EnableEvents = True
End Sub

Locking specific cells in excel VBA

I have a macro I am working on currently.
Purpose
The objective in that once there is a value in column L , i need cells in the revelant row to lock. However this should not lock the whole worksheet, just the cells.
Code
Below is the code i have been been playing with. I am trying amend the code so to achieve my purpose above.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Row = 1 Then
If Target.Column = 3 Or Target.Column = 5 Then
Beep
Cells(Target.Row, Target.Column).Offset(0, 1).Select
End If
End If
End Sub
Example
The cells which will be locked are in yellow, if there is a date in column L
The reason why locking the whole worksheet wont overcome the problem is because any additional users will not be able to input there own data into the worksheet.
Merely locking the cells has no effect unless you protect the sheet. Firstly, unlock all the cells in the sheet, and then try this:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 12 Or Target.Row = 1 Then Exit Sub
Range(Cells(Target.Row, 2), Cells(Target.Row, 11)).Locked = True
ActiveSheet.Protect
End Sub
Change the password in the first line of code with the actual password to unprotect the sheet.
Const PW As String = "123"
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.CountLarge > 1 Then Exit Sub
Dim r As Long
If Target.Column = 12 And Target.Row > 1 Then
ActiveSheet.Unprotect Password:=PW
r = Target.Row
If Target <> "" Then
Range("B" & r & ":K" & r).Locked = True
Else
Range("B" & r & ":K" & r).Locked = False
End If
ActiveSheet.Protect Password:=PW
End If
End Sub

How to prefix cell with 0, dependant on character length

Private Sub Worksheet_Change(ByVal Target As Range)
If Len(Target) = 8 Then
Exit Sub
End If
If Range("AF1:AF1000").Value = "Q" Then
Exit Sub
End If
On Error Resume Next
Application.EnableEvents = False
If Target.Column = 30 Then
lTarget = Len(Target)
Target.NumberFormat = "#"
For i = 1 To 8 - lTarget
Target.Value = "0" & Target.Value
Next
End If
Application.EnableEvents = True
End Sub
I'm trying to get this to basically when putting the information into a certain cell, if you put any less that 8 digits in, it will prefix it with '0 until it is 8 which is does, but now i want to adapt it so that it doesn't do it if a certain cell has the text "Q" in it, its not working when i do this how ever, little help?
EDIT: to make this easier the whole AF thing... its the entire AF column not just 1 to 1000 so how do i change that with what i have so far... probably need to re-write the whole thing..lol :(
If you mean it should check column AF on the same row for a Q, try this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rCell As Range
If Not Intersect(Target, Me.Columns(30)) Is Nothing Then
On Error Resume Next
Application.EnableEvents = False
For Each rCell In Intersect(Target, Me.Columns(30)).Cells
Select Case Len(rCell.Value)
Case 0, 8
' ignore if 8 characters or blank
Case Else
If Strings.UCase$(Cells(rCell.Row, "AF").Value) <> "Q" Then
rCell.NumberFormat = "#"
rCell.Value = VBA.Right$("0000000" & rCell.Value, 8)
End If
End Select
Next rCell
End If
Application.EnableEvents = True
End Sub

Emptying specific cells in the same row of an amended cell

I am relatively new to VBA.
Below is my code that works on just row 2.
Option Explicit
Public precedent
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Me.[D2]) Is Nothing Then
If Me.precedent <> Me.[D2].Value Then
Me.[F2] = ""
Me.[H2] = ""
Me.precedent = Me.[D2].Value
End If
End If
End Sub
I would like this code to run on every row except row 1 as this is my header.
How do I do this? Would I use a loop?
It shouldn't be so complicated. Just check Target.Row and Target.Column. If the former is greater than 1 and the latter is equal to 4, trigger whatever action you want.
Modify the following code accordingly.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row > 1 And Target.Column = 4 Then
Range("F" & Target.Row) = vbNullString
Range("H" & Target.Row) = vbNullString
End If
End Sub
Let us know if this helps.
You wouldn't have to use a loop. Since you want to omit the first row, you should set a range that you want this code to fire when it is modified. Currently, you are checking it against D2 only. When your If statement is checking for your entire range, you can then use Target as the specific cell that was changed (instead of using D2.)
Here's some code that should do what you want:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rangeToCheck As Range
rangeToCheck = Range(Cells(2,4),Cells(Application.ActiveSheet.UsedRange.Rows.Count,4)) 'If your range isn't dynamic, you could put static numbers here
If Not Intersect(Target, rangeToCheck) Is Nothing Then 'Now checks against all of Column D, omitting Row 1
If Target.precedent <> Target.Value Then
Target.Offset(0,2).Value = "" 'Clear Column F in Target Row
Target.Offset(0,4).Value = "" 'Clear Column H in Target Row
Target.precedent = Target.Value
End If
End If
End Sub
Below is code that will skip row 1. Note the .Row and .Column properties of 'Target'
Option Explicit
Public precedent
Private Sub Worksheet_Change(ByVal Target As Range)
Debug.Print Target.Column
Debug.Print Target.Row
If Target.Row <> 1 Then
If Not Intersect(Target, Me.[D2]) Is Nothing Then
If Me.precedent <> Me.[D2].Value Then
Me.[F2] = ""
Me.[H2] = ""
Me.precedent = Me.[D2].Value
End If
End If
End If
End Sub
I think you need this one:
Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 4 Then Exit Sub
If Me.Cells(Target.Row, 4) = "" Then
Me.Cells(Target.Row, 6) = ""
Me.Cells(Target.Row, 8) = ""
End If
End Sub