I have a worksheet with cells that may contain text that sometimes exceeds the width and height of the cell. If I don't notice it and adjust the row height, the text shows up as cutoff. Does anyone have a VBA snippet or tool that can locate these cells so I can adjust them? Thanks!
Identifying which column is too wide would be tricky, especially since the text within the cell can have different fonts and/or font sizes. It is much easier to automatically size the columns by making use of the Range.AutoFit method.
As an example, you can call the AutoFit method as follows:
Dim myRange As Excel.Range
Set myRange = Application.Range("A1:C3")
myRange.Columns.AutoFit
The Range.AutoFit method can be a bit too aggressive, however, resulting in columns that are too narrow. Therefore, you might want to create a method that establishes a minimum column width:
Sub AutoFitColumns(theRange As Excel.Range, minColumnWidth As Double)
theRange.Columns.AutoFit
Dim column As Excel.Range
For Each column In theRange.Columns
If column.ColumnWidth < minColumnWidth Then
column.ColumnWidth = minColumnWidth
End If
Next column
End Sub
The above could be called as follows, to autofit the columns, but with a minimum width of 8.5:
Dim myRange As Excel.Range
Set myRange = Application.Range("A1:C3")
Call AutoFitColumns(myRange, 8.5)
You can also autofit the Rows of the Range. This is needed less often, but to do so you'd use something like:
myRange.Rows.AutoFit
Hope this helps!
Update: Reply to Craig's Comment:
Thansk Mike. This spreadsheet is used
as sturctured input to a web interface
generator so the column widths vary
and shouldn't be adjusted. I'm really
just looking for something to scan a
sheet for any cells where the text
displayed is wider than what the cell
will allow to fit, thereby needing the
row height sized larger. I'm not
looking for a process to make the
adjustment, just find them since they
are easy to overlook. Any ideas on
that?
Well, clearly you want to do two things: (1) identify which cells are being cut off, and then (2) correct these cutoffs.
I do understand your desire to do this in two distinct stages, but step (1) is almost impossible to do correctly across all circumstances with Excel because not only can row heights and column widths vary, but text wrapping can be on or off, and the font can be a non-proportional font in any number of potential styles and/or sizes.
In short, there will be no way to reliably identify which cells are being cut off, not without an incredible amount of work. It could be mitigated, however, if you restrict the spreadsheet to only one font style and use a non-proportional font. If you do this, then you could simply compare the column width to the length of the text within the cell. This is because the Excel.Range.ColumnWidth property returns its width calibrated so that one unit of column width is equal to the width of one character in the Normal style. For proportional fonts, the width of the character 0 (zero) is used.
Therefore, for simple cases, where word wrap is not employed and the font is in the Normal style, and, ideally, the Normal font is a non-proportional font, then you could loop through all cells in the range looking for where the value held is longer than the column width:
Dim myRange As Range
Set myRange = Application.Range("A1:E5")
Dim cell As Excel.Range
For Each cell in myRange.Cells
If Len(CStr(cell.Value)) > cell.ColumnWidth Then
MsgBox "The cell at " & cell.Address & " has text that is too long!"
End if
Next cell
But now here comes the next part... How will you correct this? If, again, you have a very simple situation where word wrap is not employed and the font is in the Normal style, and, ideally, the Normal font is a non-proportional font, then you have a few options:
(1) Set the column width to match the cell's value length:
Dim myRange As Range
Set myRange = Application.Range("A1:E5")
Dim cell As Excel.Range
For Each cell in myRange.Cells
If Len(CStr(cell.Value)) > cell.ColumnWidth Then
cell.ColumnWidth = Len(CStr(cell.Value))
End if
Next cell
(2) Auto-fit the Column:
Dim myRange As Range
Set myRange = Application.Range("A1:E5")
Dim cell As Excel.Range
For Each cell in myRange.Cells
If Len(CStr(cell.Value)) > cell.ColumnWidth Then
cell.Columns.AutoFit
End if
Next cell
But if we are going to auto-fit the column, then it is much easier to just call it directly, without checking the column widths first, because not only will the widths be corrected for all cells at one time, but the Range.AutoFit method can handle any font, including non-proportional fonts, in any style.
Therefore, going directly to the auto-fit approach, we have two options: either autofit the columns, or autofit the rows. Based on your most recent quote, it sounds like you want to re-size the rows:
I'm really
just looking for something to scan a
sheet for any cells where the text
displayed is wider than what the cell
will allow to fit, thereby needing the
row height sized larger.
For this I would employ text-wrapping and then autofit the rows. For example,
Dim rng As Excel.Range
Set rng = Application.Range("A1:E5")
With rng.Rows
.WrapText = True
.AutoFit
End With
I think that these are about all your options. In the end, what you want to do and what Excel is capable of doing might not match exactly, but I think you should be able to get done what you need to? Let us know if it does the trick...
-- Mike
Related
I have an attendance form. Cells A1-G1, which will get an X for present. I have it set up to calculate the attendance percentage. I also have it set up to change the calculation based on number of days eligible ie new person starts mid month, they would only have 15 days, changing the numerator. I have to manually change the range for the countif statement.
A1:G1 is the range
J1 is the area we'd put in for how many days eligible (this is for those who are not on the whole term)
I3 is the default days eligible (regular whole term)
=COUNTIF(A1:G1,"X")/(IF(J1="",I3,J1))
This works fine, I'd like to set it up to change the countif to only count the range that has white cells vs other colors. Change the A1:G1 to say C1:G1 if cells A1, B2 were red.
I can explain for if needed. I see lots on how to change the color of a cell, but not to act on a color in countif.
D
Excel doesn't have in-built functionality for handling colors within formulas. You need to use VBA. But a note of caution, the following UDF won't recalculate unless you manually refresh. The proposed solution also uses SUMPRODUCT instead of COUNTIF:
Public Function HasNoFill(ByVal rng As Range) As Boolean()
Dim temp() As Boolean
ReDim temp(1 To rng.Count)
Dim cell As Range
For Each cell In rng
Dim i As Long
i = i + 1
temp(i) = cell.Interior.Color = 16777215
Next
HasNoFill = temp
End Function
What I am doing is very simple - selecting a union of columns which contain numbers stored as text and converting them. Every time this runs, all even union numbered columns of data are getting cleared.
Union(Columns(19), Columns(22), Columns(25), Columns(28), Columns(31), Columns(34), Columns(37), Columns(40), Columns(43), Columns(46)).Select
With Selection
.Value = .Value
End With
I've looked though my entire code multiple times are cant figure why this is behaving so weird. any help is greatly appreciated.
The Value property of a discontiguous range only returns the first area of that range. When you then try and assign that value (array, in this case) back to a discontiguous range, you get strange results. For this particular case, every second column will get the value of the first cell in the first area.
You should loop through the areas in your range.
For each rArea in Selection.Areas
rarea.value2 = rarea.value2
Next rarea
Try to avoid using Select, and fully qualify your ranges. This makes things easier to diagnose and more robust...
Dim myRange As Range
With ThisWorkbook.Sheets("Sheet1")
Set myRange = Union(.Columns(19), .Columns(22), .Columns(25)) ' etc.
End With
Now if you're trying to convert text to numbers, you might be better off using the NumberFormat property as discussed here: What are .NumberFormat Options In Excel VBA?
Looping through range areas and number-formatting:
Dim area As Range
For Each area In myRange.Areas
area.NumberFormat = 0 ' for numbers, could still use area.Value = area.Value
Next area
This is just part of my code. the value from the textbox here already gets copied to the specific cell in the Bank Certification worksheet. I need to make sure that cell C5 is specifically fitted regardless of the length of the text i inputted in the textbox. I tried interchanging range with cells to no avail. This problem seems so simple but I don't know why it doesn't work...
Dim counterparty As String
counterparty = Sheet1.txt1.Text
Range("C5").Value = counterparty
Sheets("Bank Certification").Select
Range("C5").Select
Selection.AutoFit
Try
Dim counterparty As String
counterparty = Sheet1.txt1.Text
Range("C5").Value = counterparty
Sheets("Bank Certification").Select
Columns("C:C").Autofit
Other answers correctly state that AutoFit must be used with a column, not just a cell. However, there are some nuances to using AutoFit that I didn't understand until I started experimenting.
Either of the first two statements below will use all values in column C to AutoFit the width of the column. That means if there is a value in some other cell in column C (for example C10) that is wider than the value in C5, it will fit the column to the widest cell in column C (for example C10).
Range("C5").EntireColumn.AutoFit ' Will fit to widest cell in column
Range("C:C").AutoFit ' Will fit to widest cell in column
If you want to just fit the column on 1 cell (or a certain range of cells, but not the whole column or columns), use a statement like this:
Range("C5").Columns.AutoFit ' Will fit column C to width of cell C5
And of course, it's always better form to write code like this when you can:
Fully qualify the range unless you're absolutely sure you'll only be working with one worksheet
Use Named Ranges or Range objects.
For example:
Workbooks("MyWorkbook.xlsm").Sheets("Sheet1").Range("MyData").Columns.AutoFit
' or
Set AutoFitRange = Workbooks("MyWorkbook.xlsm").Sheets("Sheet1").Range("C5")
AutoFitRange.Columns.AutoFit
Basically, I want to make a code that selects the Excel's cells according to the content.
I found to hard to explain in words, so I uploaded this image.
I want to select with a red border all the lines that contains the check mark. But if one line with the check mark is followed by another with the check mark, just do a big selection. (like I did manually in the image)
Any solution?
Thanks in advance
I know I said otherwise in the comments, but now that I've thought about it some more, this is entirely achievable with conditional formatting.
The idea is you'll set all the borders beforehand and then use conditional formatting to remove the borders that you don't want.
First, set the borders for each row how you want them to appear when there is no checkmark.
When the "Pass" column is "No", you want to remove the left and right border. Set up a conditional format using a formula rule to achieve this. Make sure to lock column D because the formula is being applied to multiple columns and you always want to look at column D.
If the current row has "Yes" in the pass column and the row below it also has "Yes", you want to remove the bottom border. You can use an additional conditional format to do this.
You'll need to cover a few more cases with additional conditional formulas, but this is the general idea.
My approach would be this: First write a sub that puts a red border around the outside of any range. It should look something like this:
Sub ApplyBorder(inputRg as Range)
Call inputRg.BorderAround(Weight:=xlMedium, Color:=vbRed)
End Sub
Now we can iterate through our range. If we find a check, include it in the range to be given a border. If we find an x, then apply the red border around the range we have, and reset it to nothing.
Sub FormatTable()
Dim AllTable As Range, oneRedRg As Range, oneRow As Range
Dim iRow As Integer
Set AllTable = GetTable
For iRow = 1 To AllTable.Rows.Count
Set oneRow = AllTable.Rows(iRow)
If oneRow.Cells(1, 3) = True Then
If oneRedRg Is Nothing Then 'if our current redRg is unset,
Set oneRedRg = oneRow 'then this is the first one, so set it
Else
Set oneRedRg = Range(oneRedRg, oneRow) 'if it is already set, then expand oneRedRg to include this one
End If
Else
if Not oneRedRg Is Nothing Then Call ApplyBorder(oneRedRg) 'if we find a range that need not be red, then
Set oneRedRg = Nothing 'apply the border to our redRg and reset it to nothing
End If
Next iRow
If Not oneRedRg Is Nothing Then Call ApplyBorder(oneRedRg) 'this last line captures a group of reds
'that are at the end of the table.
End Sub
I have excluded the "GetTable" function. In my answer, GetTable returns the entire table to be iterated through, without the headers. Also note that I changed the checks and x's to be values "True" or "False" in the spreadsheet for ease.
Happy Coding!
CF with these four rules may serve, where what is not visible is the code point for the ticks (maybe '252'):
and the ranges adjusted, if necessary, to suit.
Each cell contains some text and a background color. So I have some cells that are blue and some that are red. What function do I use to count the number of red cells?
I have tried =COUNTIF(D3:D9,CELL("color",D3)) with no success (Where D3 is red).
Excel has no way of gathering that attribute with it's built-in functions. If you're willing to use some VB, all your color-related questions are answered here:
http://www.cpearson.com/excel/colors.aspx
Example form the site:
The SumColor function is a color-based
analog of both the SUM and SUMIF
function. It allows you to specify
separate ranges for the range whose
color indexes are to be examined and
the range of cells whose values are to
be summed. If these two ranges are the
same, the function sums the cells
whose color matches the specified
value. For example, the following
formula sums the values in B11:B17
whose fill color is red.
=SUMCOLOR(B11:B17,B11:B17,3,FALSE)
The worksheet formula, =CELL("color",D3) returns 1 if the cell is formatted with color for negative values (else returns 0).
You can solve this with a bit of VBA. Insert this into a VBA code module:
Function CellColor(xlRange As Excel.Range)
CellColor = xlRange.Cells(1, 1).Interior.ColorIndex
End Function
Then use the function =CellColor(D3) to display the .ColorIndex of D3
I just created this and it looks easier. You get these 2 functions:
=GetColorIndex(E5) <- returns color number for the cell
from (cell)
=CountColorIndexInRange(C7:C24,14) <- returns count of cells C7:C24 with color 14
from (range of cells, color number you want to count)
example shows percent of cells with color 14
=ROUND(CountColorIndexInRange(C7:C24,14)/18, 4 )
Create these 2 VBA functions in a Module (hit Alt-F11)
open + folders. double-click on Module1
Just paste this text below in, then close the module window (it must save it then):
Function GetColorIndex(Cell As Range)
GetColorIndex = Cell.Interior.ColorIndex
End Function
Function CountColorIndexInRange(Rng As Range, TestColor As Long)
Dim cnt
Dim cl As Range
cnt = 0
For Each cl In Rng
If GetColorIndex(cl) = TestColor Then
Rem Debug.Print ">" & TestColor & "<"
cnt = cnt + 1
End If
Next
CountColorIndexInRange = cnt
End Function
I was needed to solve absolutely the same task. I have divided visually the table using different background colors for different parts. Googling the Internet I've found this page https://support.microsoft.com/kb/2815384. Unfortunately it doesn't solve the issue because ColorIndex refers to some unpredictable value, so if some cells have nuances of one color (for example different values of brightness of the color), the suggested function counts them. The solution below is my fix:
Function CountBgColor(range As range, criteria As range) As Long
Dim cell As range
Dim color As Long
color = criteria.Interior.color
For Each cell In range
If cell.Interior.color = color Then
CountBgColor = CountBgColor + 1
End If
Next cell
End Function
Yes VBA is the way to go.
But, if you don't need to have a cell with formula that auto-counts/updates the number of cells with a particular colour, an alternative is simply to use the 'Find and Replace' function and format the cell to have the appropriate colour fill.
Hitting 'Find All' will give you the total number of cells found at the bottom left of the dialogue box.
This becomes especially useful if your search range is massive. The VBA script will be very slow but the 'Find and Replace' function will still be very quick.