Display a checkmark for any value - excel

Using the cell format Excel allows any value to be displayed as any predetermined character. For many years I have used this feature to display a checkmark but now the code below is giving me a headache.
With Rng
.HorizontalAlignment = xlHAlignCenter
.NumberFormat = """" & ChrW(252) & """"
With .Font
.Name = "Wingdings"
.Bold = True
End With
End With
Everything is in the same workbook:
There is an account, a journal of sorts. My code filters out entries for one subject and writes the result to a dedicated sheet. The account has a column with checkmarks of this type and they are copied correctly to the tab with the filtered data. From the filtered extract my code copies items into a third tab where the info is displayed in context. Data, values only, are transferred via an array. As a result of this method the destination tab receives and displays the cell values. The above code intends to format the affected cells to show a checkmark.
Everything works fine except that the font doesn't appear to be applied. The formatted cells do show Wingdings as applied font. The value is present and suppressed but instead of a checkmark it displays nothing.
The cell format is set correctly. Since it was present in the workbook before it's noteworthy that no new format was added. (The use of ChrW() is a legacy from a problem in forgotten years past. Chr() produces the same result in the circumstance.) I tried to set the font before or after the NumberFormat.
I found that my present version of Excel (365) doesn't seem to have a checkmark in its Wingdings. Surprise because it's there in the same workbook but I didn't find it in Symbols. Instead I found Chr(80) in Wingsdings2. Applied with the same code the cells display "P", with Wingsdings2 shown as applied font.
Of course I checked the formatting of similar cells in the account and the filtered copy minutely and discovered no difference. I also tried to format the final cells again, using the same settings, but they stubbornly look at me with a blank stare.
As a coup de grace I applied the same code above to the ActiveCell on a blank sheet in the same workbook and it worked beautifully, Bold and all. So, what might be different on the worksheet on which it doesn't work? Actually, that is my question here.
Rows are inserted one by one, filled cell by cell, and a different format applied to each before the value is written. But stepping through the code with F8 produced no revelations. I also tried to enable ScreenUpdating (normally turned off while the code runs) but no different result. So, why isn't the specified font applied correctly?
The cells do have two peculiarities. One is that they are the last ones in the row. The other is that all other cells in the row are merged. This leads to a Merge command being applied to the single cell. To show the measure of my desperation I added If Rng.Cells.Count > 1 Then Rng.Merge. Of course, it made no difference.

Related

How to insert a formula by macro?

The issue has been solved.
It would appear that when I made some changes to capture data a little while ago, I inadvertently broke the order of things. When the above bit of code was running, the [Date Out:] column was indeed empty, so Excel was reporting properly.
I've since reordered the input of formulas and now the sheet works correctly, with credit to #BigBen and #Michael Wycisk.
I created an Excel sheet to draw together the data from several other Excel sheets into one to keep track of a project.
I have a formula that works if it is written into a range of cells with the source data sheet open in the background. If I ask a macro to put it into the required cells as the main sheet opens then the formula fails. By 'fail', I mean the formula checks it's first column to see if data is present or not and then decides that the column is empty regardless, therefore falsely reporting 'nothing sent' if there is a date in the "Date Out" column.
Here is the line in question.
WSR.Range("ReportTable[Latest Portare Instance:]") = "=IFERROR(IF([Date out:]="""",""Nothing Sent"",IF(AND([Received by Serial:]="""",[Received by Asset:]=""""),""Not Received"",IF([Received by Asset:]<>"""",LOOKUP(2,1/('Stock Movement Archive Defra.xlsx'!Archive[Asset No:]=$J2),'Stock Movement Archive Defra.xlsx'!Archive[Location:]),LOOKUP(2,1/('Stock Movement Archive Defra.xlsx'!Archive[S/No:]=$I2),'Stock Movement Archive Defra.xlsx'!Archive[Location:])))),""Issue"")"
It's one of several formulas, all inserted the same way and the rest work. As far as I can tell the formula is being inserted correctly, just that this one stops at the first if statement.
For reference, I have tried changing the first 'if' statement to start IF([Date out:]<>"""", the formula then either states "Nothing Received" where there is no date or pulls the correct data if there is a date. Also tried changing the format of the "Date Out" column.
The formula looks fine for me. The only problem might be that you need to use the .Formula property after the Range object:
WSR.Range("ReportTable[Latest Portare Instance:]").Formula = "=IFERROR(IF([Date out:]="""",""Nothing Sent"",IF(AND([Received by Serial:]="""",[Received by Asset:]=""""),""Not Received"",IF([Received by Asset:]<>"""",LOOKUP(2,1/('Stock Movement Archive Defra.xlsx'!Archive[Asset No:]=$J2),'Stock Movement Archive Defra.xlsx'!Archive[Location:]),LOOKUP(2,1/('Stock Movement Archive Defra.xlsx'!Archive[S/No:]=$I2),'Stock Movement Archive Defra.xlsx'!Archive[Location:])))),""Issue"")"
To make sure that your formula is correct (you say it works fine when typed into the cell), you might type it into the cell, select the cell and then type ?ActiveCell.Formula into the Immediate Window inside the VBE (don't forget to check that the quotation marks are correct).

How do I reference an Excel ListObject table column if the column name has line breaks?

I'm tasked with the following:
several sheets from different workbooks have to be copied to a new workbook
each of those sheets contains an Excel table (a ListObject), named like the sheet with a postfixed T (sheet Foo, table: FooT)
the new workbook has to contain a summary sheet where each table name is listed, and various values of the respective tables are presented by referencing them with suitable formulas
This has to be done frequently for different workbooks, so the idea was to do this in VBA.
Copying the sheets is easy, listing the table names in a new sheet is easy, but referencing the values runs into problems.
The general idea is to do the following
ActiveSheet.Range("A1").Value = "FooT"
ActiveSheet.Range("B1").Formula = "=FooT[[#Totals],[Quantity]]"
ActiveSheet.Range("C1").Formula = "=FooT[[#Totals],[Total List Price]]"
and iterate over all sheets.
Setting the value for A and the formula for B works as expected and gets the expected results.
The issue with C is that instead of "Total List Price", the column header is actually formatted as
"Total
List
Price"
I can't change that, this has been a design decision.
This is also how the column name shows up in the formula if I add the formula to the cell manually.
So there's some sort of line break happening here, and I've tried cater to this in VBA with
ActiveSheet.Range("C1").Formula = "=FooT[[#Totals],[Total" & vbCrLf & _
"List" & vbCrLf & _
"Price]]"
and vb_Cr and vb_Lf and vb_Newline instead of the vbCrLf. Trying to set C's formula to any of these variations yields the infamous Error 1004.
Getting the value of the column header from one of the sheets and using it in the formula works. This could be a potential workaround, but I'd really like to know what I'm missing or how I can figure out how to build this formula string correctly.
Your formula is OK but typically, the newline character will be vbLf if the title was set from the keyboard. I also suspect there might be leading and/or trailing space characters anywhere in the title. Select your title cell and, from the VBE's Immediate Window (Ctrl+G), type Debug.Print ActiveCell.Value, then check where each printed line ends.
Are you using Option Explicit? In your question, you mention you've tried vb_Lf but this constant doesn't exist and, without Option Explicit, would have been interpreted as an empty string.
When you enter a line break in a cell, the text is actually continuous to the previous line, there being no separator character, unless you enter a space before the break. To name the column you must write it without a space between the last word of the previous line and the first of the next, like this: [TotalListPrice]

How to use relative names in Excel VBA

Many "advanced" (aka: VBA) excel tutorials on the web or even excel's vba help encurage us to use the
Range("B2:B10")
method (to be precise: object) for selecting cells or getting values. In the same place they often add it's totally ok to use predefined names as well:
Range("valuesabove")
On the other hand I fell in love with the incredible power of relatively defined cell names. They make it so much easier to write and handle big composite formulas, and basically to refer to nearly anything.
However, relative names don't work in the Range("valuesabove") method the way we are used to it.
Usually (when used on the worksheet) relative names are relative to the currently selected cell or to the cell in which they are used.
In VBA's Range() object this is not true. Range is relative to a WorkSheet object, by default to the ActiveSheet. But ActiveSheet is represenetd by its leftupper cell, A1. And this is what Range turns out to be relative to. And this is why absolute names ($C$23) do work with it, and relative ones ("one column to the left, two rows up") don't.
So my question is:
How can I harness the power of relative names in VBA then?
EDIT:
Realising that my question was rather unclear (thx's go to you guys commenting tirelessly) let me try to put it in a specific form and clarify terms:
IMHO on an excel worksheet it is very comfortable to use names in order to refer to cells or define calculated values by functions based on cell values.
In excel a reference to a cell can be either relative, absolute, or mixed. This is true also when creating names. Thus we can speak about absolute, relative or mixed names (in terms of referring of course).
Here an absolute name is used a couple times (created using excel's Trace Dependents function):
Name "name" = $D$2
A relative name is used a couple times here:
Name "upright24" while, e.g. cell A7 is selected = C3 (without $ signs!). But this changes constantly according to the selected cell or region. You can check it in the name manager! (Ctrl+F3)
And this is what we can consider as a mixed name:
Name "rel_serialnumber" while, e.g. cell C6 is selected = $B6. The row of which (6) changes constantly according to the selected cell or region.
The creation of a relative or a mixed name is explicitly based on the active cell at the moment of creating the name. The creation of an absolute name naturally doesn't rely on the cursor position.
Note, that
absolute names mean a dinamic offset from the referenced cell, which is one and only
relative names mean a static offset from the referenced cell, which thus changes always corresponding to the place where the name is used
mixed names mean a mixed (or half-dynamic) offset from the referenced cell, the row or column of which thus changes always corresponding to the place where the name is used while the other remains always the same (the offset in one or the other direction remains zero).
Okay, now here is the thing. I have a database-like excel sheet where I handle the rows like records and the columns as fields for properties. The user uses this thing as follows: he "selects a record" by placing the cursor in any cell of the row of the desired record. Then he presses a big command button which starts my VBA macro. This intends to open a prepared skeleton file and fill some specific cells in it (which are btw defined by absolute names) with some values (which are defined by mixed names) from the selected record.
Since Range("name") is considered ok to use in VBA (see above) I thought Range("relativename") or Range("mixedname") will work just as fine while automatically relying on the active cell.
I couldn't be worse.
Only Range("absolutename") works in the way one would expect! Explanation see above.
So I'm after a function / method / object that is possibly as comfortable to use with a "relativename" or a "mixedname" as Range("absolutename") is.
It appears you are looking for Range.Offset() http://msdn.microsoft.com/en-us/library/office/ff840060%28v=office.15%29.aspx
However you could do it as:
'Your example Range(Col_B_in_current_row) as
Range("B" & ActiveCell.Row).Select
'Your example Range("B2:B10") -> Range("valuesabove") as
Range("B2:B10").Offset(-1, 0).Select
Just seems like a relatively simple syntax already exists for this.
I think I've found a proper and compact solution. It's
Names("mixedname").RefersToRange
Not as short as Range("mixedname") would be but it is really providing the expected values.
UPDATE:
This solution is mostly unuseful if you want to copy relative-named cell values in a source workbook to relative-named cells in a dest workbook with a single codeline. This is because Names() relies on the actual position of the cursor which is depending on which workbook is currently the active one and in most cases this won't be ok for the other.
In this case the non-fixed part of the name has to be stored:
sourcerow = ActiveCell.Row
[...]
'opening a wbk, this also makes it the active one
[...]
Names("dest").RefersToRange = mysheet.Cells(sourcerow, mybook.Names("src").RefersToRange.Column)
To reference a Range relative to another Range you can use this syntax:
myRange.Range("namedRange")
Note: This only works if both the Row offset AND the Column offsets are positive. For example if the "Refers to" formula for the named range is "=Offset(A1,r,c)", then the above syntax will throw an error if Either r Or c is negative. But, it will work if both are positive.
The asymmetry is unfortunate but business as usual for VBA...
To Reference the third column in the row of the current ActiveCell:
ActiveCell.EntireRow.Range("C1")
To reference a cell offset by (for example) 1 row and 3 columns relative to the ActiveCell:
ActiveCell.Range("C2")
Obviously, you can use the same syntax with the Selection Object or any other Range value in VBA.
Private Sub Worksheet_Change(ByVal Target as Range)
If Not Intersect(Target.Address,ThisWorkbook.Sheets('sheetname).Range('RangeName)) Is Nothing Then _
'Do whatever you want down here.
ThisWorbook.Sheets('sheetname).Range('RangeName).Offset(0,Target.Row)
End If
End Sub
This should send you on the right path to what you want (which is super unclear). Use the worksheet change event to bring in user worksheet selections and changes into VBA modules. Put it into the relevant sheet.
I had the same problem, but I did get it to work - sort of. I don't know what is different about the simple example below, but it works. At first I thought selection mattered, but no - it works without changing the active cell.
(I still can't get it to work in my main spreadsheet.)
Named range: "TestName" = Sheet1!$H1
Values in H1:H10 = 1,2,3,4,5,6,7,8,9,10
Sub Test()
Dim x As Integer
For x = 0 To 10
Range("A1").Offset(x, 0).Value = Range("A1").Offset(x, 0).Range("Testname").Value
Next x
End Sub
Result: A1:A10 = 1,2,3,4,5,6,7,8,9,10

VBA - Sum Cells with the 'Number Stored as Text' error

In Excel 2010, I am writing VBA to take the SUM of a range of filtered values, and store that result into a variable. The code looks like this:
With Sheets("Output")
.Range("$A:$ZZ").AutoFilter field:=ColIndex(AB), Criteria1:="x"
y = Application.WorksheetFunction.Sum( _
Range(Cells(2, "AC"), Cells(10, "AC")).SpecialCells(xlCellTypeVisible) _
)
This does work, but only when I have manually toyed with the data. When I try to use this formula on my data set unedited, I get a blank result. The problem seems to lie with the data when unedited.
Each number gets the Number Stored as Text (NSaT) error. Changing the type from Text to General causes nothing to happen. I have to open the cell for editing, and then remove focus from the cell for the type to kick in. After that, I can change it back and forth from General to Text, and Excel immediately recognizes this and updates the cell. The Sum function will, at this point, recognize both General and Text field types as a number.
Is there a VBA solution for dealing with these NSaT errors? I have attempted to use 'NumberFormat' on the column, but it does not help. I have also tried manually copying and pasting the data again, even using the special As Value option, but it still has the NSaT error until manually toyed with.

How to make sure all excel cells formatted as text in a column actually are

I have a column of content submitted by multiple users, generally pasted into a sheet, from multiple sources. This column has numbers that should always be formatted as text.
In fact, no matter how this is done, there are always a few items that never have the indicator in the left corner warning that these are formatted as text (which we want to see in all cases)
Checking the individual cell, it does show as formatted text, but in reality on an import into a datatable, if the indicator is missing, the datatype is imported as a number.
Clicking after the number and hitting Enter will change the indicator to text.
How can I do that in VBA? I don't want to visit each cell, click on the end of the content and hit enter.Cutting and paste special in no combination reliably fixes these.
What does excel look at, which gets the format issue right with these text format warning indicators, and yet doesn't seem to get it right when you look at the cell format properties?
Excel 2003 but have had the same issue in later versions too.
What worked for me was to check the error indicator, which seemed more reliable than the cell format itself. This looks for anything missing the indicator and forces it to be text.
Unless someone knows something further concerning why this should NOT be done, it solves my issue.
Sub check4textformat()
For Each cell In Range("E2:E15000")
If cell.Errors.Item(xlNumberAsText).Value = False Then cell.Formula = cell.Text
Next
End Sub
You really only need to prepend the text indicator character "'" before every number. Assuming that your values are in the first column, in the first 120 rows, you can do it like this:
For i = 1 To 120
Me.Cells(i, 1).Value = "'" & Me.Cells(i, 1).Value
Next i
If the cell already has a text value, the prepending is ignored. When copying (and when obtaining the value in VBA) the "'" is completely ignored as it only indicates the "type" of the cell contents.
Since your main target is not visiting each cell, I will suggest an easier way than VBA (actually, it's probably the easiest way).
Select the desired column.
Go to Data > Text to Columns.
Select "Delimited" (should be already selected by default) and press "Next".
Uncheck all delimiters and press "Next" (you can also leave the default state of "Tab" as the only delimiter).
Under "Column Data Format", select "Text" and click "Finish".
Done. All the numbers in the column should be stored as text now.

Resources