Attempting to step through columns in a search - vba

I am attempting to create a module in Excel 2016 that will scan through a sheet and auto size any comments found. My current code requires me to adjust the Column Letter each time I run it. I am looking for a method to step through the columns in my loop. My current code is listed below and I am thanking anyone ahead of time for any assistance I can get. My current sheet only uses columns A through P.
Sub cmtsize()
ActiveSheet.Unprotect pswd
Range("a7:I7").Select
lrow = Cells(Rows.Count, 1).End(xlUp).Row
For xrow = 7 To lrow
xcell = "c" & lrow
Range(xcell).Select
If ActiveCell.Comment Is Nothing Then
GoTo nxt
Else
With Range(xcell).Comment.Shape
.TextFrame.AutoSize = True
End With
nxt:
End If
Next xrow
ActiveSheet.Protect pswd
Range("A6").Select
MsgBox "Finished!"
End Sub

This will resize all comments on the specified worksheet. [Update] included option for password protected sheets. As well as the Finished Msgbox.
Sub test()
Call ResizeComments(Sheet1)
MsgBox ("Finished!")
End Sub
Private Sub ResizeComments(ByVal ws As Worksheet, Optional ByVal Pass As String = "")
If Pass <> "" Then ws.Unprotect Pass
Dim oComment As Comment
For Each oComment In ws.Comments
oComment.Shape.TextFrame.AutoSize = True
Next
If Pass <> "" Then ws.Protect Pass
End Sub

Related

How can I combine 3 VBA subroutines into one?

The first sub collects all the worksheets of the workbooks that are located in D:\Users\Cons\excel.
Then the second sub looks for the word "filename" in worksheet 2 then copies all the cells below to A2 in worksheet 3.
Finally the last sub should search for the word "apple" in e2:e100 in worksheet 3, and delete every row where "apple" is not found.
I have created 3 buttons and assigned the subs to each one of them. The first 2 runs fine, doing what I want, but when I click on the 3rd button (with 3rd sub behind), nothing happens,
only the first two buttons above are being shifted upwards, don't know why.
How can I combine all the 3 subs into one (that is actually working with a button click)? Thanks in advance!!!
Sub ConslidateWorkbooks()
Dim FolderPath As String
Dim Filename As String
Dim Sheet As Worksheet
Application.ScreenUpdating = False
FolderPath = "D:\Users\Cons\excel\"
Filename = Dir(FolderPath & "*.xls*")
Do While Filename <> ""
Workbooks.Open Filename:=FolderPath & Filename, ReadOnly:=True
For Each Sheet In ActiveWorkbook.Sheets
Sheet.Copy After:=ThisWorkbook.Sheets(1)
Next Sheet
Workbooks(Filename).Close
Filename = Dir()
Loop
Application.ScreenUpdating = True
Worksheets(1).Activate
End Sub
Sub FindInFirstRow()
Dim fCell As Range
Dim strFind As String
Dim wsSource As Worksheet
Dim wsDest As Worksheet
'What shall we look for?
strFind = "filename"
'What sheet are we getting data from/to?
Set wsSource = Worksheets(2)
Set wsDest = Worksheets(3)
Set fCell = wsSource.Range("1:1").Find(what:=strFind, lookat:=xlPart, MatchCase:=False)
If fCell Is Nothing Then
MsgBox "No match found"
Else
'Copy the cells *below* to A2 of destination sheet
Intersect(wsSource.UsedRange.Offset(1), fCell.EntireColumn).Copy wsDest.Range("a2")
End If
End Sub
Sub SaveSomeRows()
Dim N As Long, L As Long, r As Range
Dim s As String, v As String
Set r = ActiveSheet.Range("e2", ActiveSheet.Range("e100").End(xlUp))
N = r.Count
s = "apple"
For L = N To 1 Step -1
v = LCase(r(L).Value)
If InStr(1, v, s) = 0 Then
r(L).EntireRow.Delete
End If
Next L
End Sub
Sub TheOneSub()
ConslidateWorkbooks
FindInFirstRow
SaveSomeRows
End Sub
Sub ConslidateWorkbooks()
...
End Sub
Sub FindInFirstRow()
...
End Sub
Sub SaveSomeRows()
...
End Sub
Sub combine_all()
Call ConslidateWorkbooks
Call FindInFirstRow
Call SaveSomeRows
'Runs them sequentially
End Sub
Assign this to a button , this would run (call) the other codes in sequence

How can I stop editing cell if it is not done with in set time?

In my office we tally bags with a barcode scanner, but some times the user edits the Excel cell, giving the bag number manually, so I want to stop manually writing in excel cell.
That cell must update only by scanner.
I've tried the code below, and it returns the keystroke count but not the time.
Private Sub Worksheet_Change(ByVal Target As Range)
'If Target.Address = Range("A1:A100") Then
'Enter Code or Call any Function if any process has to be performed
'When someone Edits the cell A1
If Range(ActiveCell, ActiveCell.Offset(numRows, numCols)).Offset.Value = "" Then
Call Demo
Else: End If
End Sub
Sub Demo()
'Specify a range (change to suit)
MsgBox CountKeystrokes(Sheets("Sheet1").Range("A:A"))
If Range(ActiveCell, ActiveCell.Offset(numRows, numCols)).Offset.Value <> "" Then
Range(ActiveCell, ActiveCell.Offset(numRows, numCols)).Select
Selection.ClearContents
Else
End If
End Sub
Function CountKeystrokes(rng As Range) As Long
Dim rCell As Range
Dim iCtr As Long
For Each rCell In rng
iCtr = iCtr + Len(rCell.Formula)
Next
CountKeystrokes = iCtr
End Function

Excel Macro: Copy sheet without links - just data

I would like to copy one specific sheet in MS Excel to a new file. The following Macro does the job, but the problem is that the copy always links the cells to the original file. Is there a way to insert only the values of this sheet without the links?
Sub Copy_sheet()
ThisWorkbook.Sheets("Overview").Copy
ActiveWorkbook.SaveAs "C:\testfolder\testfile.xlsx", FileFormat:=51
End Sub
Thank you!
Add the following to your code before the End sub:
With ThisWorkbook.Worksheets("Overview").UsedRange
.Value = .Value
End With
It would change the formulas to values. If you want to do it for the whole workbook, this is the way to go:
Public Sub CopyJustData()
Dim lngCount As Long
For lngCount = 1 To Worksheets.Count
With Worksheets(lngCount).UsedRange
.Value = .Value
End With
Next lngCount
End Sub
One way is this.
Sub Copy_sheet()
Dim wbNew As Workbook
ThisWorkbook.Sheets("Overview").Copy
Set wbNew = ActiveWorkbook
With wbNew
With .Worksheets(1).UsedRange
.Value = .Value
End With
.SaveAs "C:\testfolder\testfile.xlsx"
End With
End Sub
Sub SaveCopy
ThisWorkbook.Sheets("your sheet name").Select
ActiveSheet.Copy
ActiveSheet.SaveAs FileName:="your path to save "& ".xlsx" 'xlsx or your other
BreakLinks '
End Sub
Sub BreakLinks()
On Error Resume Next
Dim vLinks As Variant
Dim lLink As Long
' Define variable as an Excel link type.
vLinks = ActiveWorkbook.LinkSources(Type:=xlLinkTypeExcelLinks)
If vLinks = vbNullString Then Exit Sub
' Break all links in the active workbook.
For lLink = LBound(vLinks) To UBound(vLinks)
ActiveWorkbook.BreakLink _
Name:=vLinks(lLink), _
Type:=xlLinkTypeExcelLinks
Next lLink
End Sub

Only allow sub to run after another has been run VBA

I've created a workbook that imports data from another file and then deletes any rows by finding a header string "Time". However, if the macro that deletes the rows is run again it will remove the header as there's a sub-header called "Time" as well.
OR is there a way to limit the characters Find searches for i.e. say my subheader is Real Time and my char limit is 4, find should only return "real" and therefore ignore that?
What I want to do is disable the Row Delete code unless there has been a new data import and the Row Delete hasn't already been run.
Some psuedo code below
If (DataImport has been run){
If (rowDelete has been run since DataImport){
return;
}
else{
run rowDelete
}
}
Excel VBA
Sub ImportData()
Dim wb1 As Workbook
Dim wb2 As Workbook
Dim sheet As Worksheet
Dim pastestart As Range
Set wb1 = ActiveWorkbook 'Sheets("Data")
Set pastestart = [Data!A1]
FileToOpen = Application.GetOpenFilename _
(Title:="Please choose a data file")
If FileToOpen = False Then
MsgBox "No File Specified.", vbExclamation, "error"
Exit Sub
Else
Set wb2 = Workbooks.Open(Filename:=FileToOpen)
For Each sheet In wb2.Sheets
With sheet.UsedRange
.Copy pastestart
Set pastestart = pastestart.Offset(.Rows.Count)
End With
Next sheet
End If
wb2.Close
End Sub
_____________________________________________________________________
Sub rowDelete()
Dim FindRow As Range
On Error Resume Next
With Sheets("Data")
Set FindRow = Cells.Find(What:="Time", After:=.Cells(1, 1), LookIn:=xlValues, LookAt:= _
xlPart, MatchCase:=False)
End With
On Error GoTo 0
Range("A1", FindRow).EntireRow.Delete
End Sub
You could include a cell on a worksheet which states whether an import has been made since the last row delete; include a line of code at the end of your ImportData procedure which updates this cell.
ThisWorkbook.Sheets(1).Range("A1") = "Imported"
Then at the end of the rowDelete procedure you can update this cell to reflect that the rows have been deleted.
ThisWorkbook.Sheets(1).Range("A1") = "Rows deleted"
Then within the rowDelete procedure you can check if the last procedure to be run was rowDelete. If it was, do not run the procedure.
If ThisWorkbook.Sheets(1).Range("A1") = "Rows deleted" Then
Exit Sub
End If
If the cell shows that the ImportData procedure was run last (because the cell shows "Imported") then the rowDelete procedure can run.
How about using CustomDocumentProperties instead. Makes it more invisible:
ThisWorkbook.CustomDocumentProperties("Imported")
You can make this a yes/no property
YOu could use global variables to identify, will the below work for you?
Make sure you call InitiParams at the begining of the cycle
Dim Option Explicit
'Module Level Variables
Dim boolDataImportComplete as boolean
Dim boolRowDeleteRunComplete as boolean
Sub InitParams()
boolDataImportComplete = False
boolRowDeleteRunComplete = False
End Sub
Sub ImportData()
''' Your Code here
boolDataImportComplete = True
End Sub
Sub RowDelete()
''' YOUR Code here
boolRowDeleteRunComplete = True
End Sub

Test data in variable range for missing information and notify submitter

I am new to VBA and building off of someone else's code, who was newer to VBA than me! Thanks in advance for any tips and advice you may have.
Since I cannot post the image I will attempt to describe the dataset. The data is from a userform, with the bulk of the content in a table range A14:M34, with questions in column A, and data in columns B-M. The first row is a header the user populates identifying the unit inspected. The data below is populated with pull downs with blank, Yes and NO as options, and a few rows with numeric or character strings.
I want to test each cell in a variably sized range for unanswered questions and notify the user if there are any and give them the option to complete the dataset before submitting.
Sub new_p()
Static AbortProc As Boolean
Dim iRow As Long
Dim LastColumn As Long
Dim aCol As Long
Dim ws As Worksheet, WS1 As Worksheet
Dim InputRange As Range
Set ws = Worksheets("PreparationData")
Set WS1 = Worksheets("ColdWeatherPreparation")
Set InputRange = WS1.Range("B15:M34")
If AbortProc Then Exit Sub
'find last column in range
LastColumn = WS1.Cells(14, 2).End(xlToRight).Column
'define variable range of columns
For aCol = 2 To LastColumn
'check that the circuit row is not blank
'If Cells(14, aCol) Is Not Nothing Then
If IsEmpty(InputRange) Then
Msg = "All fields are not populated. Stop submission to resume editing?"
Ans = MsgBox(Msg, vbYesNo)
'if yes stop process
If Ans = vbYes Then
AbortProc = True
Exit Sub
End If
'if no run rest of script
If Ans = vbNo Then
MsgBox "Run without Correcting?"
AbortProc = False
Exit Sub
End If
End If
'End If
Next
'more code here that seems to be working
End Sub
You'll see I have commented out a line I think is redundant. If End(xlToRight) generates the last populated column of the header row then they are not blank, so no need to test. Nonetheless I keep code I am not using until the final checks are done and it is proven to be completely useless. The excessive commenting is to help a large group of non-VBA staffers follow and verify my code before implementing.
So the LastColumn definition seems to work, and I use it again later. When I step through the code it cycles through the correct number of times for my bogus dataset. I feel like the isEmpty is where I am falling down.
If every cell in B15:M34 should be non-blank, then you can do this:
If Application.CountBlank(InputRange)>0 Then
If Msgbox(Msg, vbYesNo) = vbYes Then
'rest of your code
End If
End If
EDIT: this will check each data cell against the corresponding header cell.
Sub new_p()
Static AbortProc As Boolean
Dim iRow As Long
Dim LastColumn As Long
Dim aCol As Long
Dim ws As Worksheet, WS1 As Worksheet
Dim InputRange As Range, rw As Range
Dim HeaderRange As Range
Dim x As Long, Msg As String
Set ws = Worksheets("PreparationData")
Set WS1 = Worksheets("ColdWeatherPreparation")
Set HeaderRange = WS1.Range("B14:M14")
Set InputRange = WS1.Range("B15:M34")
'are you sure about this next line?
'once validation has failed once how does it re-run?
If AbortProc Then Exit Sub
For Each rw In InputRange.Rows
For x = 1 To rw.Cells.Count
If Len(rw.Cells(x).Value) = 0 And _
Len(Headerange.Cells(x).Value) > 0 Then
Msg = "All fields are not populated. Stop submission" & _
" to resume editing?"
If MsgBox(Msg, vbYesNo) = vbYes Then
AbortProc = True
Exit Sub
Else
MsgBox "Run without Correcting?"
AbortProc = False
Exit Sub
End If
End If
Next x
Next rw
'more code here that seems to be working
End Sub
Errors at Len line? Maybe, because Cells has 2 parameters? Cells(RowIndex,ColumnIndex).
Also, you can set LastColumn by:
LastColumn = ActiveSheet.UsedRange.Columns.Count
same thing can be done for rows:
LastRow = ActiveSheet.UsedRange.Rows.Count
Maybe you should move If AbortProc Then Exit Sub inside For loop (as first/last line)