VBA and Excel columns - excel

In the Excel-sheet for the A column write procedure, which with MsgBox function returns the column, A1 drawers from the first address of an empty drawer?

This is not an answer. I am trying to help you ask your question. Do not worry if your English is poor. If you say enough we can guess what you mean. One sentence is not enough.
Below I have tried to use short, simple sentences. I hope you can understand me. Are my guesses correct? If not, I hope this helps you write a clearer question.
Is this homework? A first exercise with Excel? Have you translated it with a dictionary? "Drawer" is an English word but there are no drawers in Excel. Do you mean "cell"? A1 is a cell. B5 is a cell. You put things in a drawer. You put things in a cell. This is the sort of mistake English - Xxxxxx dictionaries make.
Create and open a new Excel workbook. Click Alt+F11. On the right at the top you will see a grey area. On the right at the bottom you will see a white area labelled "Immediate". Down the left you will see something like:
VBAProject (Your excel file)
Microsoft Excel Objects
Sheet1 (Sheet1)
Sheet2 (Sheet2)
Sheet3 (Sheet3)
ThisWorkbook
If you left-click Sheet1 and then right-click, you will see a menu something like:
View Code
View Object
--------------------
VBProject Properties
: :
: :
Click View Code. The grey area will turn white. Here you can enter code for Sheet 1. Is this what you mean by "in the Excel-sheet"?
I am not going to put code against Sheet1. I am going to use a Module.
Go to the Toolbar and click Insert. In the Menu, click Module.
The window down the left will now look like:
VBAProject (Your excel file)
Microsoft Excel Objects
Sheet1 (Sheet1)
Sheet2 (Sheet2)
Sheet3 (Sheet3)
ThisWorkbook
Modules
Module1
"Module1" will be grey because it is selected.
I think you have been asked to: "Find the first empty cell in Row 1 and display its column number with MsgBox." There are many ways of doing this. Which is the simpliest? I do not know. Here are two ways:
Option Explicit
' Both these routines work on the ActiveSheet. That is, the worksheet
' you can see when you switch to Excel. If this code had been against
' Sheet1, it would have worked on Sheet 1 even if another sheet had been
' active.
Sub FindFirstEmpty1()
' This routine uses Offset. Range("A1").Offset(RowOffset, ColOffset) says
' I want to look at the cell which is RowOffset rows down from A1 and
' ColOffset columns right from A1.
Dim ColOffset As Long
ColOffset = 0
Do While True
If Range("A1").Offset(0, ColOffset).Value = "" Then
Call MsgBox("The first empty column is " & ColOffset + 1, vbOKOnly)
Exit Sub
End If
ColOffset = ColOffset + 1
Loop
End Sub
Sub FindFirstEmpty2()
' This routine uses Cells(Row, Column). The columns are numbered: A=1, B=2,
' C=3 and so on. Cells(Row, Column) lets me look at any cell in the
' worksheet.
Dim ColCrnt As Long
ColCrnt = 1
Do While True
If Cells(1, ColCrnt).Value = "" Then
Call MsgBox("The first empty column is " & ColCrnt, vbOKOnly)
Exit Sub
End If
ColCrnt = ColCrnt + 1
Loop
End Sub

Related

Preventing selection of previous cell in Excel after changing tabs

and thanks for the answers
I am designing a LogBook using excel VBA and this is the problem:
I work on Sheet2 and let's say I left the editing on cell F2 and go to Sheet1 to do other stuff. After I come back to Sheet 2 the selection remains on cell F2 but I don't want this. Actually, I don't want any cell to be selected. Since the selection of a cell marks the borders of that cell it does not look good on my design. I want to show A1 to Z40 without any cell selected. Hope I could describe it.
Any suggestiions?
Change Selection When Returning to Tab
Copy the following code to the Sheet2 code module.
Option Explicit
Private Sub Worksheet_Activate()
' You have to activate (select) something:
Cells(Rows.Count, Columns.Count).Activate ' last cell on worksheet
' or e.g.:
'Range("AA1").Activate
With ActiveWindow
.ScrollColumn = 1
.ScrollRow = 1
End With
End Sub

How to run a macro in a specific Sheet, but control the start based on a Value maintained from another Excel File/Sheet?

Hi,
How to run a macro in the background in a specific Sheet, and only work with and control the trigger of the Macro based on a calculated Value maintained in another Excel File/Sheet?
The use case is that I want to run a Macro named “TargetCalc” – which trigger either Marcro_01 or Marcro_02 in a specific Sheet depending if Cell C3 in that Sheet has the value 1 or 2.
The Macro example below works nice if everything is maintained or calculated within the active Excel Sheet itself. But - if I instead want to control the value in Cell C3 from a completely another Excel File I have open (where my focus is), then I get the error message “Run-time error ’9 ’: Subscription out of range”
The Test setup:
Save an Excel File named “DisplayExcelFile.xlsm” and rename “Sheet1” to “DisplaySheet1”
Copy the VBA Code seen below
In the File “DisplayExcelFile.xlsm” - in Cell C3, enter: =IF(D3<100,1,2)
In the File “DisplayExcelFile.xlsm” - in Cell D3, enter the value 105
Result:
a) Cell C3 will display 2 because Cell D3 is 105, which is more than 100 => Macro_01 is triggered
b) If you manually update Cell D3 from 105 to 78 => Macro_02 is triggered
So far so good – and this example works nice.
Open a 2nd Excel on the same machine – and rename “Sheet1” to “CalcSheet” and Save this Excel File with the name “CalcFromExcelFile.xlsm”
In the File “CalcExcelFile.xlsm” - in Cell A2, enter the value 130
Next: Have both Excel Files opened on the same machine – and Go back to the first Excel File “DisplayExcelFile.xlsm” Cell D3 and change Cell D3 from a value (105 or 78…) to instead a formula that refers to the other Cell A2 in the other opened Excel File: =[CalcFromExcelFile.xlsm]CalcSheet!$A$2
Result:
a) As long as the “focus” is within Sheet named “DisplaySheet1” in the first “DisplayExcelFile.xlsm” – the functionality works as expected when updating the Cell D3 with different numbers.
b) BUT: If you instead have “focus” in the second Excel File “CalcExcelFile.xlsm” and update the Cell A2 in the second Excel File to the Value 97 – Then the macros in the Sheet “DisplaySheet1” in the first “DisplayExcelFile.xlsm” does not work.
The popup VBA error says:
Run-time error ’9 ’: Subscription out of range
And when I “Debug” – it points to the row for the Macro_01:
“Worksheets("DisplaySheet").Range("A3").Select”
In addition:
The workflow I’m after is to have both Excel Files opened on the same machine – where the First Excel File “DisplayExcelFile.xlsm” is for Display Purpose and running the Macros – but all manual updates (the focus) is on the second Excel File “CalcFromExcelFile.xlsm”.
The Sheet will always be named “DisplaySheet1” in the first “DisplayExcelFile.xlsm” – so there is no need to modify the code so that it will work in case I rename the Sheet. My hope is that when I get this use case working, I will then create a 2nd and 3rd Sheet (“DisplaySheet2” and “DisplaySheet2” within the same First Excel File – so that I can replicate the same thing for these Sheets as well.
When I tried to get the VBA code working - I tried to make a direct reference to the Sheet name – and I also tried to improve the usage of “Select”, but I got stuck.
The Code
Module1
Option Explicit
Public TargetValue As Variant
Private Const cTarget As String = "C3"
Sub TargetCalc(ws As Worksheet)
'
If ws.Range(cTarget) <> TargetValue Then
Application.EnableEvents = False
Select Case ws.Range(cTarget).Value
Case 1
Macro_01
Case 2
Macro_02
End Select
TargetValue = ws.Range(cTarget).Value
Application.EnableEvents = True
End If
End Sub
Sub Macro_01()
'
Worksheets("DisplaySheet").Range("A3").Select
ActiveCell.FormulaR1C1 = "Hi_01"
Application.Wait Now + TimeValue("0:00:01")
ActiveCell.FormulaR1C1 = "There_01"
End Sub
Sub Macro_02()
'
Worksheets("DisplaySheet").Range("A3").Select
ActiveCell.FormulaR1C1 = "Hi_02"
Application.Wait Now + TimeValue("0:00:01")
ActiveCell.FormulaR1C1 = "There_02"
End Sub
Sheet1 (DisplaySheet)
Option Explicit
Private Sub Worksheet_Calculate()
TargetCalc Me
End Sub
ThisWorkbook
...empty...
Thanks a lot!
Don't select anything, [almost] ever. If you tell VBA the address, VBA will find it. Therefore you need to sort through your workbooks and worksheets with great care. I usually do this before I start programming. That's why you find the definitions at the top of my code below.
Don't worry about the sheet names. The first tab on the left is always Worksheets(1). You can address it by its index number. I think you will probably stick with names like "DisplaySheet1" in the display book but use the index in the calculation workbook. Point is: identify workbooks and worksheets precisely. Note that a worksheet, once defined with a Set statement, knows the workbook to which it belongs and you can retrieve that book's name with `Ws.Workbook.Name'.
Note that ThisWorkbook identifies the workbook in which the code resides whereas ActiveWorkbook is the one that has the focus. They could be the same but must not be the same necessarily.
Don't bother with macro numbers. Instead, learn about arguments. A macro that does essentially one job, like your Macro_01 and Macro_02, can be combined into one macro with the 1 or 2 supplied as an argument.
The code below will help you on your way.
Option Explicit
Sub Main()
' 149
Dim WsDisplay As Worksheet
Dim WsCalc As Worksheet
Dim Arg As String
Set WsDisplay = ThisWorkbook.Sheets(1)
Set WsCalc = ActiveWorkbook.Sheets(1)
If WsDisplay.Cells(3, "D").Value < 100 Then
Arg = 1
Else
Arg = 2
End If
' ' Note: I would use the following in place of the above
' ' because it's only a single line
' Arg = 2 + (WbDisplay.Worksheets(1).Cells(3, "D").Value < 100)
Action WsDisplay, Arg
End Sub
Private Sub Action(WsDisplay As Worksheet, _
ByVal Switch As Integer)
' 149
Dim Target As Range
Dim Txt As String
Select Case Switch
Case 1
Set Target = WsDisplay.Cells(3, 1) ' 1 = column A
Txt = "Hi"
Case 2
Set Target = WsDisplay.Cells(3, 2) ' 2 = column B
Txt = "Hello"
Case Else
MsgBox "Invalid switch"
Exit Sub
End Select
With Target
.Value = Txt
.Offset(1).Value = "there!"
End With
End Sub
Look for the worksheet and workbook definitions in the Main procedure. The design is to let the CalcSheet be the active one but, later in the code, that sheet is never used. All the action is on the inactive DisplaySheet.
Macro_01 and Macro_02 need to know which workbook they're operating on.
Eg:
Sub Macro_01()
With ThisWorkbook.Worksheets("DisplaySheet").Range("A3")
.Value = "Hi_01"
Application.Wait Now + TimeValue("0:00:01")
.Value = "There_01"
End With
End Sub

Trying to hide text in an excel cell

I am looking at running test on survey results. For the column headers for each question they are IMP1, IMP2, etc. What I want to be able to do is place the question in this cell so that when you click on the header you can see the question but from the overview of the file all the user can see is IMP1.
Not sure if that wording makes sense but basically I want the text in the formula section when you click on a cell. When the cell isn't selected it should just show IMP1.
This is specifically for the single cell A1, but can be expanded to process all the cells in column A. First enter this in the cell:
IMP1What is the meaning of life ??
and then place the following Event Macro in the worksheet code area:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim A1 As Range
Set A1 = Range("A1")
l = Len(A1.Text)
If Intersect(A1, ActiveCell) Is Nothing Then
A1.Characters(Start:=1, Length:=l).Font.ColorIndex = 1
A1.Characters(Start:=5, Length:=l).Font.ColorIndex = 2
Else
A1.Characters(Start:=1, Length:=l).Font.ColorIndex = 1
A1.Characters(Start:=1, Length:=4).Font.ColorIndex = 2
End If
End Sub
If you click on A1, you will see:
and if you click off the cell, you will see:
Because it is worksheet code, it is very easy to install and automatic to use:
right-click the tab name near the bottom of the Excel window
select View Code - this brings up a VBE window
paste the stuff in and close the VBE window
If you have any concerns, first try it on a trial worksheet.
If you save the workbook, the macro will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the macro:
bring up the VBE windows as above
clear the code out
close the VBE window
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
To learn more about Event Macros (worksheet code), see:
http://www.mvps.org/dmcritchie/excel/event.htm
Macros must be enabled for this to work!
Besides using Comments you could use a VBA subroutine to do this based on the worksheet's SelectionChange event. In your VBE, double click the worksheet where this event is taking place in the VBAProject pane. In that code window place the following:
'Global Variable to hold the last column A cell that was clicked into
Private lastClicked As Range
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'Did we click out of a column A cell?
If Not lastClicked Is Nothing Then
If Target <> lastClicked Then
'Copy the holder value from column C back to Column A
lastClicked.Value = lastClicked.Offset(, 2).Value
Set lastClicked = Nothing
End If
End If
'Detect a click into column A
If Target.Column = 1 Then
'Update the global "lastClicked" variable
Set lastClicked = Target
'Move the holder text to column C
Target.Offset(, 2) = Target.Value
'Move the question text from column B to target
Target.Value = Target.Offset(, 1).Value
End If
End Sub
This set up is assuming that your questions (the holder text like IMP1) is in Column A of the worksheet, and that you would have the entire question hidden (I assume) in Column B. Also that Column C would be empty so that we could temporarily hold the holder text (although you could stuff that into it's own global variable as well).

Macro for Excel: If Column B has "X", then copy entire row and paste in Worksheet named "Column B"

I have limited experienced of writing macros, and I'm looking to update a current spreadsheet used at work. Currently we copy the entire Master worksheet and paste it into other worksheets before sorting for the "X" in certain columns to delete other rows on the master worksheet.
What I am looking to do is search the Master Sheet, and if Column B has an "X" then copy the entire row and paste it into a worksheet named "Column B". Then, once Column B was completed and pasted, it would look at Column D. If Column D had an "X", it would copy the entire row and paste it in worksheet tab named "Column D".
Thanks in advance!
Approach
I should have included this in the first version of my answer.
My solution depends on AutoFilter. I first offer a play solution that demonstrates this approach by:
making rows not containing X in column B invisible
making rows not containing X in column D invisible
clearing the AutoFilter
If this approach appeals, I refer you to my answer to another question which creates a menu so the user can select which filter they want.
If this approach does not appeal, I offer a second solution which involves copying the visible rows left by each filter to other worksheets.
Introduction
You say "I have limited experienced of writing macros" which I take to mean you have some experience. I hope I have the level of explanations correct. Come back with questions if necessary.
I assume your workbook is on a server. I assume someone has write access to update the master worksheet while others open read-only copies so they can look at the subsets of interest to them. If my assumptions are about right, take a copy of the workbook for you to play with. Don't worry about others updating the master version of the workbook, we will copy the final version of the code from your play version when we have finished.
Step 1
Copy the first block of code to a module within the play version. Near the bottom you will find Const WShtMastName As String = "SubSheetSrc". Replace SubSheetSrc by the name of your master worksheet.
Note: the macros within this block are named CtrlCreateSubSheetB and CreateSubSheetB because they are play versions. The real versions are named CtrlCreateSubSheet and CreateSubSheet.
Run macro CtrlCreateSubSheetB. You will see the Master worksheet but only those rows with an "X" in column B. Click on the message box.You will see the Master worksheet but only those rows with an "X" in column D. Click on the message box and the filter will disappear. Switch to the VB Editor if you are not already there. In the Immediate Window (Click Ctrl+G if it is not visible) and you will see something like:
Rows with X in column 2: $A$1:$G$2,$A$4:$G$5,$A$8:$G$9,$A$11:$G$12,$A$14:$G$14, ...
Rows with X in column 4: $A$1:$G$1,$A$3:$G$3,$A$5:$G$5,$A$7:$G$7,$A$10:$G$10, ...
Now work down macros CtrlCreateSubSheetB and CreateSubSheetB. You must understand how these macro have created the effects you saw. If necessary use VB Help, the Debugger and F8 to step down the macros to identify what each statement is doing. I believe I have given you enough information but come back with questions if necessary.
' Option Explicit means I have to declare every variable. It stops
' spelling mistakes being taken as declarations of new variables.
Option Explicit
' Specify a subroutine with two parameters
Sub CreateSubSheetB(ByVal WShtSrcName As String, ByVal ColSrc As Long)
' This macro applies an AutoFilter based on column ColSrc
' to the worksheet named WShtSrcName
Dim RngVis As Range
With Sheets(WShtSrcName)
If .AutoFilterMode Then
' AutoFilter is on. Cancel current selection before applying
' new one because criteria are additive.
.AutoFilterMode = False
End If
' Make all rows which do not have an X in column ColSrc invisible
.Cells.AutoFilter Field:=ColSrc, Criteria1:="X"
' Set the range RngVis to the union of all visible rows
Set RngVis = .AutoFilter.Range.SpecialCells(xlCellTypeVisible)
End With
' Output a string to the Immediate window.
Debug.Print "Rows with X in column " & ColSrc & ": " & RngVis.Address
End Sub
' A macro to call CreateSubSheetB for different columns
Sub CtrlCreateSubSheetB()
Const WShtMastName As String = "SubSheetSrc"
Dim WShtOrigName As String
' Save the active worksheet
WShtOrigName = ActiveSheet.Name
' Make the master sheet active if it is not already active so
' you can see the different filtered as they are created.
If WShtOrigName <> WShtMastName Then
Sheets(WShtMastName).Activate
End If
' Call CreateSubSheet for column 2 (=B) then column 4 (=D)
Call CreateSubSheetB(WShtMastName, 2)
Call MsgBox("Click to continue", vbOKOnly)
Call CreateSubSheetB(WShtMastName, 4)
Call MsgBox("Click to continue", vbOKOnly)
With Sheets(WShtMastName)
If .AutoFilterMode Then
.AutoFilterMode = False
End If
End With
' Restore the original worksheet if necessary
If WShtOrigName <> WShtMastName Then
Sheets(WShtOrigName).Activate
End If
End Sub
Step 2
If my assumptions about how you use the workbook are correct you may not need much more. If John and Mary each open a read-open copy of the master workbook then John could use the B filter while Mary uses the D filter. If this sounds interesting, look at my answer to copy row data from one sheet to one or more sheets based on values in other cells.
Step 3
If you do not like the idea of just using filters and still want to create copies of the B data and the D data, you will need the code below.
The macros within this block are named CtrlCreateSubSheet and CreateSubSheet but are not much different from the B versions above.
In CtrlCreateSubSheet you will need to replace "SubSheetSrc", "SubSheetB" and "SubSheetD" with your names for these worksheets. Add further calls of CreateSubSheet for any further control columns.
Note: these version delete the original contents of the destination sheets although this is not what you have asked for. I have deleted the original contents because (1) what you have adding new rows is more complicated and (2) I do not believe you are correct. If there is some significance to what you requested then come back and I will update the code.
Option Explicit
Sub CtrlCreateSubSheet()
Const WShtMastName As String = "SubSheetSrc"
' Call CreateSubSheet for column 2 (=B) then column 4 (=D)
Application.ScreenUpdating = False
Call CreateSubSheet(WShtMastName, 2, "SubSheetB")
Call CreateSubSheet(WShtMastName, 4, "SubSheetD")
With Sheets(WShtMastName)
If .AutoFilterMode Then
.AutoFilterMode = False
End If
End With
Application.ScreenUpdating = True
End Sub
Sub CreateSubSheet(ByVal WShtSrcName As String, ByVal ColSrc As Long, _
ByVal WShtDestName As String)
' This macro applies an AutoFilter based on column ColSrc to the worksheet
' named WShtSrcName. It then copies the visible rows to the worksheet
' named WShtDestName
Dim RngVis As Range
Dim WShtOrigName As String
With Sheets(WShtSrcName)
If .AutoFilterMode Then
' AutoFilter is on. Cancel current selection before applying
' new one because criteria are additive.
.AutoFilterMode = False
End If
' Make all rows which do not have an X in column ColSrc invisible
.Cells.AutoFilter Field:=ColSrc, Criteria1:="X"
' Set the range RngVis to the union of all visible cells
Set RngVis = .AutoFilter.Range.SpecialCells(xlCellTypeVisible)
End With
If RngVis Is Nothing Then
' There are no visible rows. Since the header row will be visible even if
' there are no Xs in column ColSrc, I do not believe this block can
' be reached but better to be safe than sorry.
Call MsgBox("There are no rows with an X in column " & ColSrc, vbOKOnly)
Exit Sub
End If
' Copy visible rows to worksheet named WShtDestName
With Sheets(WShtDestName)
' First clear current contents of worksheet named WShtDestName
.Cells.EntireRow.Delete
' Copy column widths to destination sheets
Sheets(WShtSrcName).Rows(1).Copy
.Rows(1).PasteSpecial Paste:=xlPasteColumnWidths
' I do not recall using SpecialPaste column widths before and it did not
' work as I expected. Hunting around the internet I found a link to a
' Microsoft page which gives a workaround. This workaround worked in
' that it copied the column widths but it left row 1 selected. I have
' added the following code partly because I like using FreezePanes and
' partly to unselect row 1.
WShtOrigName = ActiveSheet.Name
If WShtOrigName <> WShtDestName Then
.Activate
End If
.Range("A2").Select
ActiveWindow.FreezePanes = True
If WShtOrigName <> WShtDestName Then
Sheets(WShtOrigName).Activate
End If
' Copy all the visible rows in the Master sheet to the destination sheet.
RngVis.Copy Destination:=.Range("A1")
End With
End Sub
Step 4
Once you have deleveloped the macros to your satisfaction, you will need to copy the module containing the macros from your play version to the master version. You can export the module and then import it but I think the following is easier:
Have both the play and master versions of the workbook open.
Create an empty module in the master version to hold the macros.
Select the macros in the play version, copy them to the scratchpad and then paste them to the empty module in the master version.
You will need to teach whoever is responsible for updating the master version to run the macros whenever a significant update is complete. You could use a shortcut key or add the macro to the toolbar to make the macro easy to use.
Summary
Hope all that makes sense. Do ask questions if necessary.
More simply:
Sub Columns()
If WorkSheets("Sheet1").Range("B1") = x Then
WorkSheets("Column B").Range("B2") = WorkSheets("Sheet1").Range("B2:B" & Rows.Count).End(xlup).Row
End if
If WorkSheets("Sheet1").Range("D1") = x Then
WorkSheets("Column D").Range("D2") = WorkSheets("Sheet1").Range("D2:D" & Rows.Count).End(xlup).Row
End if
End Sub

Transfer values from one sheet of a workbook to another by clicking on the cell

I have 5,000 part numbers contained on one sheet of an Excel workbook (Part Numbers), ranging from cell A1:A5000. I want to find a way to click on any one of those part numbers and have it automatically populate into cell D7 on another sheet of the same workbook (Price Sheet). What is the easiest way to accomplish this task?
To do it that way, you will have to write VBA code to catch every SheetSelectionChange event to see if the new selection range is in your cells A1:A5000. And then if it is, execute the VBA code to fill OtherSheet!D7.
If I recall correctly, the VBA code to do this would look something like this:
Private Sub WorkSheet_SelectionChange(ByVal Target As Range)
'Check if it is in the range A1:A5000
If Target.Column = 1 And Target.Row <= 5000 Then
'get the target worksheet
Dim TargetWS As Worksheet
Set TargetWS = Sheets("OtherSheetsName")
'copy the value of the just selected cell to D7 on the target WS
TargetWS.Cells(7, 4).Value = Target.Value
End If
End Sub
(Oops, forgot about the need for "SET" in VBA.)
You can do this without VBA:
Select the partnumbers A1:A5000 and type PartNumbers in the Name Box (to the left of the formula bar) and press carriage return (OartNumbers should now be visible in the Name Box whenever you select a1:a5000
Now go to cell D7 on Price Sheet, and use Data Validation-->List and enter =PartNumbers in the Source box
Now you can select any of the 5000 part numbers from the dropdown in cell D7

Resources