LibreOffice Calc shortcut different between edit cell and edit sheet modes? - keyboard-shortcuts

I made a simple macro to increase the value of the current cell by 1 (I need that operation quite often):
Sub activecellplus1
ThisComponent.CurrentSelection.value = ThisComponent.CurrentSelection.value +1
End Sub
and I assigned it to Ctrl+A because a) I don't need selecting the whole sheet and b) I am used to it from Vim.
This works as expected, with one problem: Ctrl+A now no longer works when editing cells (it may or may not increase the currently edited cell by 1, but it won't select its content).
Is there a way to define Ctrl+A as "Select All" for cells, but as "run this macro" for the sheet (i.e., when not editing a cell)? Alternatively, is there a way to modify the above macro to perform "Select all" when editing a cell?
I am not familiar with LibreOffice's macro language; I only did this for the described functionality.

I couldn't find a way to detect if I am currently editing a cell or I'm just positioned on one (i.e., in normal mode). Andrew Pitonyak - OpenOffice.org Macros Explained suggests that this cannot be done.
Here is an ugly solution, in hopes that someone finds a better one:
Sub HandleCtrlA
cel = ThisComponent.currentSelection
wasSingleCell = cel.supportsService("com.sun.star.sheet.SheetCell")
' Select All
document = ThisComponent.currentController.frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dispatcher.executeDispatch(document, ".uno:SelectAll", "", 0, Array())
if wasSingleCell Then
isSingleCell = ThisComponent.currentSelection.supportsService("com.sun.star.sheet.SheetCell")
If not isSingleCell Then
' We are no longer working with just one cell.
' This means that we were not in cell edit mode and our Select All has selected the whole sheet.
' Therefore, we deselect it and increase the current cell's value by one.
dispatcher.executeDispatch(document, ".uno:Deselect", "", 0, Array())
If cel.Type = 1 Then
' The active cell contains a number, but we don't know if were in edit mode or normal mode.
cel.value = cel.value + 1
Else
' Our cell is not a number. Refuse to increment and explain why.
MsgBox("The cell does not contain a numerical value.", MB_OK + MB_ICONEXCLAMATION, "Error")
End If
End If
End If
End Sub
This is good enough for what I need, but be careful if you decide to use it: it still messes up "Select All" in the macro editor and possibly elsewhere.

Related

VBA macro not triggering when target cell changes via form control option buttons

I literally just got my feet wet with VBA as this is my first macro. After many hours of searching, I couldn't seem to find an answer that had a solution that worked for me so here I am.
On Sheet3 I have 3 option buttons in a group box that are linked to cell "B18" on Sheet4 (Sheet4 is hidden to the user, a backstage if you will). When any of the three option buttons are selected, 'Sheet4!B18' gets updated as it should (e.g. 1, 2, or 3). What I want to happen is to have 'Sheet3!B17' changed based upon the value in 'Sheet4!B18', or effectively: IF('Sheet4!B18'=2,SET('Sheet3!B17'="Some Text Here:"),SET('Sheet3!B17'="0%")), but still allow user input in 'Sheet3!B17'. I have one VBA macro on Sheet4 with the following code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Worksheet.Range("B18") = 2 Then
Worksheets("Sheet3").Range("B17") = "Some Text Here:"
Else
Worksheets("Sheet3").Range("B17") = "0%"
End If
End Sub
If I manually update 'Sheet4!B18' then the macro gets triggered with the desired results. If I use any of the 3 option buttons on Sheet3, the macro does not get triggered even though the target cell is getting updated.
In my searching I couldn't seem to find anything concrete, but from what I could tell the "Worksheet_Change" function doesn't see changes to cells from form control as changes to the linked cell are considered a "recalculation" as if it were from a formula. I don't know how correct that is, but my searching led me to believe that I would need another macro assigned on the 3 buttons and/or group box that when either of those get selected/changed, it would somehow trigger the working macro on Sheet4.
I thought that perhaps I could create a new macro that I would assign to the group box or option buttons themselves so I tried that and could not get anything to work. I tried adding the above macro code to another sub, Sub mode() and assigning to only the group box, then only the buttons, but nothing happened in either case. I proceeded to try tweaking the code just in case the references were not correct, but saw no change regardless of how I specified the reference. I am not getting any error messages, but nothing gets triggered unless I manually change the value in 'Sheet4!B18'.
Is there a way to get the first macro that I have working on Sheet4 to trigger off of the option buttons changing the target cell value, something like forcing it to look only at that one specific cell for changes? Am I stuck making another macro for the buttons and/or group box to trigger the macro on Sheet4? Am I over-complicating this and there is some built in Excel sheets function(s) that I can use?
IF/THEN is a fine way to do it. VBA also supports ternary logic with the IIF function, like this:
Worksheets("Sheet3").Range("B17") = IIF(Worksheets("Sheet4").Range("B18") = 2, "Some Text Here:", "0%")
That may seem a little difficult to read, but it's a good concept to understand, since it's present in many languages, and usually with a more simplified implementation that makes it very useful and concise.
Also, I would suggest making a couple of other alterations that may make your code easier to write, read and maintain (especially as it becomes more complex).
First, alias the worksheets, something like this:
Dim this as Worksheet: Set this = Worksheets("Sheet3")
Dim that as Worksheet: Set that = Worksheets("Sheet4")
Now you would be able to rewrite your code like this:
If that.Range("B18") = 2 Then
this.Range("B17") = "Some Text Here:"
Else
this.Range("B17") = "0%"
End If
And the ternary approach would now be:
this.Range("B17") = IIF(that.Range("B18") = 2, "Some Text Here:", "0%")
And you can get as specific as you like with the aliases. For instance, you could realias the ranges, instead of just the worksheets, like this:
Dim this as range: Set this = Worksheets("Sheet3").Range("B17")
Dim that as range: Set that = Worksheets("Sheet4").Range("B18")
this = IIf(that = 2, "Some Text Here:", "0%")
Also, I find it easier to use the cells property than the range property, especially when you start having to do cell math. In that case, Range("B17") becomes Cells(17, 2).
You can also change the way the cells are referenced in the spreadsheet by typing Application.ReferenceStyle = xlR1C1 into the immediate window. That way you don't have to mentally convert between A2 style ranges to Cartesian style (2,1).
Sometimes you just have to go through your entire thought process and type everything out before you have an "ah-hah!" moment because that is exactly what I had happen. I said to myself, "Why can't I have just one macro that gets triggered by the option buttons that checks my linked cell then proceeds to update the cell I want?" Well, eventually I was able to find the right code and this is what worked perfectly:
Sub mode() ' mode is the name of this macro
If Worksheets("Sheet4").Range("B18") = 2 Then
Worksheets("Sheet3").Range("B17") = "Some Text Here:"
Else
Worksheets("Sheet3").Range("B17") = "0%"
End If
End Sub
As it turns out, I was overlooking the simple solution and the above macro is all I need once I assigned it to the 3 option buttons in my group box, but not the group box itself. Since users will not have access to the hidden Sheet4 and therefore 'Sheet4!B18' will never have manual user input, the macro I first had on Sheet4 could be removed safely. Due to the fact that the option buttons being chosen is the trigger for the assigned macro, it executes each time the option is changed and only when the option is changed. Perfect!
EDIT:
Thanks to Chris Strickland for some tips for better code! I went on to modify the above into what you see below for slightly better performance (using Cells() instead of Range()), to save the original value to another cell and restore it if option 1 or 3 were selected, used aliases, and finally the IIf operator.
Sub mode() ' mode is the name of this macro
Dim S3 As Worksheet: Set S3 = Worksheets("Sheet3")
Dim S4 As Worksheet: Set S4 = Worksheets("Sheet4")
If IsNumeric(Cells(17, 2)) = True Then
S3.Activate
S4.Cells(18, 3) = Cells(17, 2).Value
End If
S3.Cells(17, 2) = IIf(S4.Cells(18, 2) = 2, "Some Text Here:", S4.Cells(18, 3))
End Sub

How to Find selected Active cell highlighted with Color and copy the data provided in the cell above to some special assigned cell

I am new to VBA so if somebody help me to solve my problem then I shall be really grateful as I am stuck with it.
enter image description here
Please have a look at the attached picture below and if somebody provide me code for VBA then it will be really helpful for me. Task contains following steps.
1- In row 11 dates are provided in corresponding columns. Like 16/11, 17/11, 18/11 etc.
2- From row (12 to 29) I have different tasks to do are provided.
My task is.
1- When I select any cell/ box by filling it with any color the date available in the (row 10) above that cell (automatically goes/copies) to the specified cell mentioned for that task.
For Example: I select Row 21 AQR presentation cell and highlight it by filling it with color so the date above that cell automatically goes/copies to specified cell mentioned above for AQR presentation and similarly I have to do with every cell.
Request:
I need a code that detects the active cell which is highlighted and sends the date above that cell to a specified folder mentioned for that above.
Please see the figure for more clear understanding.
I shall be grateful if somebody help me in providing the code for this.
I do not believe that an exact match on your requirement is possible; certainly I do not know how to provide an exact match. However, I believe something very similar is possible which I think is more convenient than your request.
You need to use event routines. Excel identifies “Open workbook”, “Activate worksheet”, “Change selection” and many others as events. For any Excel event, you can write a routine in VBA which Excel will execute when that event occurs.
If you open Excel’s VB Editor and click F2 you get a list of all the classes and their members. Scroll down the Classes list until you reach “Worksheet”. The list on the right will display all member of the Worksheet class. Those with a lightning symbol against them are events: Activate, BeforeDelete, BeforeDoubleClick, BeforeRightClick, Calculate and so on. If you type “excel vba worksheet before double click event” into your favourite search engine, you will get web pages that explain the event and usually give an example of a routine for the event. I find the documentation a little vague and I usually have to experiment with an unfamiliar event.
I have written event routines for the WorkBook Open event and the Worksheet Activate, Before Right Click and Selection Change events. Unfortunately, there is no “Worksheet Change Cell Colour” event so I have used the “Worksheet Before Right Click” event instead.
With the VB Editor open, you will see the Project explorer down the left hand side. If you cannot see it, click Ctrl+R. What you will see will be something like:
- VBAProject(Xxxxx.xlsm)
- Microsoft Excel Objects
Sheet1 (Kick off)
Sheet2 (Sheet2)
ThisWorkbook
You will have more worksheets, perhaps some user forms and some modules but they do not matter for the moment. If you can see a plus where I have shown a minus, click it to expand the list. I have created a copy of your kick-off worksheet which I have named “Kick off”. You probably have a different name but I will call it “Kick off”. Click “Sheet1 (Kick off)” and a white area will appear to the right. This is a code area reserved for this worksheet. There is a similar code area for every worksheet. If you click “ThisWorkbook”, you will get another code area. You can use this code area as an ordinary module but I advise against it. This code area should be reserved for certain workbook level routines.
Place this code within the ThisWorkbook code area:
Option Explicit
Sub Workbook_Open()
If ActiveSheet.Name = "Kick off" Then
Worksheets("Sheet1").Activate
Worksheets("Kick off").Activate
End If
End Sub
A routine with the name Workbook_Open in this code area will be automatically executed when the workbook is opened. Replace “Kick off” with your name for this worksheet and replace “Sheet1” with the name of any of your other worksheets.
If worksheet “Kick off” was active when the workbook was saved, its Activate routine is not executed automatically when the workbook is opened. The sole purpose of this code is to force execution of the “kick off” activate routine.
The code below all belongs in the code area for Worksheet “Kick off”. This code will not do exactly what you want so I will attempt to explain it in sufficient detail for you to adapt it to your requirements,
My code starts with some constants for rows and columns. For example:
Const RowDate As Long = 11 ' Row holding dates
Currently, you have your dates in row 11 but this could easily change as you develop your system. If you amend your worksheet so row 13 holds the dates, simply update this constant statement and your code is fully updated. So much easier than scanning your code for all uses of the literal 11.
Next I have some constants for colours. If you do not like my colours, amend these constant statements.
Next are some Dim statements. A variable declared within a routine, is destroyed when the routine exits. A variable declared outside a routine has a longer life. I do not know if these variables last until the workbook is closed or until another worksheet is activated. It does not matter; they last long enough to allow me to pass values from one call of an event routine to another call.
Next is Private Sub Worksheet_Activate(). If your users switch to another worksheet, this routine will be called automatically when they switch back. It records the position of the active cell and loads three arrays. The three arrays and their values are:
Array entries -> 0 1
RowActionSrc 16 21
RowActionDest 2 3
ColActionDest 25 25
The way these arrays are used is a common technique with experienced programmers but might be new to you. You want special actions to occur if a selection is made on row 16 or 21. These rows may change and similar actions may be required for other rows later. By having a single statement load these row numbers into an array, it is easy to change them or add to them. If a cell on row 16 is selected, you want its date copied to row 2, column 25. If a cell on row 21 is selected, you want its date copied to row 3, column 25. These destinations may not be what you want but they are easy to change so that does not matter. I have coded Worksheet_BeforeRightClick to use the numbers in these arrays to move the required dates to the required cells.
Stepping over Worksheet_BeforeRightClick for the moment, the last routine in this code is Worksheet_SelectionChange. I was not sure if this was a good idea. The functionality provided by this routine is the cause of most of the complexity in this code. I have decided to keep the functionality because I believe it is helpful and because it gives a very good demonstration of what event routines can do. This is an image of my kick off worksheet:
It is a little small but adequate for the purpose and does not exactly match yours but is close enough. The active cell is currently cell Z21. You will notice the task and date for this cell are coloured. When I first started, I found it difficult to match the active cell to its task and date. Colouring the task and the date made it much easier. This is what Worksheet_SelectionChange does. When the user moves the active cell, this routine is called automatically to remove the colouring from the old task and date and colour the new task and date. As I said, I believe this functionality is both helpful and a good demonstration of how you can use event routines to tailor the Excel experience.
Returning to Worksheet_BeforeRightClick; this is the routine that provides the functionality that is the closest match I can achieve to what you requested. As I said, there is no event based on colouring a cell. Even if there was, I am not sure I would find it convenient. I would have to select the Home tag then Fill Colour then the colour I wanted before the event would be triggered. With the Before Right Click event, I select the cell I wish to be active using the arrow keys or the mouse or F5 or however I wish. I then click the right mouse key. The event routine colours the cell with the standard colour and copies the date.
Experiment with my code. Try to work out how it achieves its objectives. Come back with questions as necessary but the more you can work out for yourself, the quicker you will develop your own skills.
Option Explicit
' I define these column and row numbers as constants in case they change.
' If they do change, one amendment here and the code is updated. If the
' literal is used in the code, you have to search for and fix every use
' to update the code.
Const ColDateFirst As Long = 3 ' The first column with a date
Const ColTaskName As Long = 1 ' Column holding task names
Const RowDate As Long = 11 ' Row holding dates
Const RowTaskFirst As Long = 12 ' First row containing tasks
' Warning: If you change any of these colours, the values are BBGGRR which
' is Excel's standard and not RRGGB which is everyone else's standard.
Const ClrCrntHeader As Long = &H99CCFF ' Tan
Const ClrSelectedCell As Long = &HFFFF& ' Yellow
' The position of the active cell is recorded in these variable so
' when the active cell changes the old position is known. This is
' necessary to correctly maintain the row and column headers. If
' the row and column headers were not highlighted, these variables
' would not be needed.
Dim ColPrev As Long
Dim RowPrev As Long
' These arrays are loaded by Worksheet_Activate(). See that routine
' for an explanation of these arrays.
Dim RowActionSrc() As Variant
Dim RowActionDest() As Variant
Dim ColActionDest() As Variant
Private Sub Worksheet_Activate()
' This routine is called when the worksheet is activated (selected)
' * If the active cell is within the monitored area, the header row and
' column will already be hightlighted. Record the current position of
' the active cell in ColPrev and RowPrev.
' * Load RowAction and ColAction arrays
' * The monitored area is ColDatFirst and right and RowTaskFirst amd down.
Application.EnableEvents = False
If ActiveCell.Row >= RowTaskFirst And ActiveCell.Column >= ColDateFirst Then
' Active cell was within the monitored area when the workbook was closed or
' the user switched to another worksheet. The appropriate row and column
' headers will still be highlighted.
ColPrev = ActiveCell.Column
RowPrev = ActiveCell.Row
Else
' The active cell was outside the monitored area. No row or column header
' is highlighted
ColPrev = 0
RowPrev = 0
End If
' If the active cell is right clicked when it is in one of the rows
' listed in RowActionSrc:
' 1) The active cell is coloured ClrSelectedCell
' 2) The date above the active cell is copied to the row and column
' specified in the cell specified by the matching positions
' in RowActionDest and ColActionDest.
RowActionSrc = VBA.Array(16, 21)
RowActionDest = VBA.Array(2, 3)
ColActionDest = VBA.Array(25, 25)
' For example:
' * If cell(16,20) is right clicked, the date in cell(11, 20) is copied
' to cell(2,25).
' * If cell(21,27) is right clicked, the date in cell(11, 27) is copied
' to cell(3,25).
Application.EnableEvents = True
End Sub
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
' * The active cell has been right clicked.
' * If the active cell is within the monitored area and if active row is
' specified in RowActionSrc, copy the data above the active cell to the
' specified destination cell.
Dim CellColoured As Range
Application.EnableEvents = False
Dim InxC As Long
If ActiveCell.Row >= RowTaskFirst And ActiveCell.Column >= ColDateFirst Then
' Active cell was within the monitored area
For InxC = 0 To UBound(RowActionSrc)
If RowActionSrc(InxC) = ActiveCell.Row Then
' The active cell is in a row for which the date above it is to be
' copied to a specified destination. In addition, the active cell is
' to be coloured
' First remove colour from any previously selected cell
Application.FindFormat.Interior.Color = ClrSelectedCell
Do While True
' What:="*" will only match cells with a value
' What:="" will match cells with or without a value
Set CellColoured = Rows(ActiveCell.Row).Find(What:="", SearchFormat:=True)
If CellColoured Is Nothing Then
Exit Do
End If
CellColoured.Interior.ColorIndex = xlNone ' Remove colour
CellColoured.Value = "" ' Remove value if any
Loop
' Colour selected cell
Cells(ActiveCell.Row, ActiveCell.Column).Interior.Color = ClrSelectedCell
' Move date for active column to specified cell
Cells(RowActionDest(InxC), ColActionDest(InxC)).Value = Cells(RowDate, ActiveCell.Column).Value
End If
Next
End If
Cancel = True ' Surpress default action for Right Click
Application.EnableEvents = True
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Application.EnableEvents = False
' A new cell has been selected; that is, there is a new active cell.
If ColPrev <> 0 Then
' Remove highlighting from previous task name and date
Cells(RowPrev, ColTaskName).Interior.ColorIndex = xlNone
Cells(RowDate, ColPrev).Interior.ColorIndex = xlNone
End If
If ActiveCell.Row >= RowTaskFirst And ActiveCell.Column >= ColDateFirst Then
' Active cell is within the monitored area
ColPrev = ActiveCell.Column
RowPrev = ActiveCell.Row
' Highlight task name and date
Cells(RowPrev, ColTaskName).Interior.Color = ClrCrntHeader
Cells(RowDate, ColPrev).Interior.Color = ClrCrntHeader
Else
ColPrev = 0 ' No previous active cell
RowPrev = 0
End If
Application.EnableEvents = True
End Sub
Explanation of additional functionality
The original code would colour a cell selected with a right click but would not remove the colour from a previously selected cell. The new code locates any cells in the active row coloured ClrSelectedCell (= Yellow = &HFFFF&) and removes the colour and the value if any.
Find is normally used to search for values but it is possible to search for formats. If there is any decent documentation on the format search functionality, I have failed to find it. The extra code has been developed through experimentation rather than by following official instructions. This code has been tested using Excel 2016 but I have no reason to believe it will not work with earlier versions.
The changes are the inclusion of a new variable (Dim CellColoured As Range) and the inclusion of this code just before the newly selected cell is coloured:
Application.FindFormat.Interior.Color = ClrSelectedCell
Do While True
' What:="*" will only match cells with a value
' What:="" will match cells with or without a value
Set CellColoured = Rows(ActiveCell.Row).Find(What:="", SearchFormat:=True)
If CellColoured Is Nothing Then
Exit Do
End If
CellColoured.Interior.ColorIndex = xlNone ' Remove colour
CellColoured.Value = "" ' Remove value if any
Loop
There should only be one previously coloured cell but this code loops so all previously coloured cells are cleared of colour and value.
Note: I clear the colour using ColorIndex = xlNone rather than Colour = vbWhite. If you set the colour of a cell to white, you lose the borders but you do not if you set the colour index to none.
Define a function in VBA:
Function NOTWHITE(rng As Range) As Boolean
Application.Volatile
If rng.Interior.ColorIndex = xlNone Or rng.Interior.Color = vbWhite Then
NOTWHITE = False
Else
NOTWHITE = True
End If
End Function
Then put into D12 the following formula and copy-paste to all other cells you wish to behave like that:
=IF(NOTWHITE(D12); D$11; "")
However you need to recalculate the sheet by F9 after each change.

Excel VBA How to detect if something was pasted in a Worksheet

I'll start by saying that my experience with Excel and VBA is limited to what I saw in school. I have programming experience, but in other languages.
I have a file that I get every week. The structure of this file is always the same:
ID, Name, Date, Value between 1 and 4, non-relevant data.
This data is selected through the 'select all' button (top left corner of the worksheet, little triangle below the cellname in MS excel 2013) and then copied into another default file that reworks the data to show and filter it in different sheets based on the 1-4 value and the date.
My question: How do I detect when data has/is being pasted? I've tried the Worksheet.Change event, but the paste command (CTRL+V) does not trigger the Change event.
Also, how will the data be copied? Will it update Row by row, cell by cell (which direction), ...?
I know I can easily find the answer to the last question by debugging it once I can detect the copy command, but you never know if someone knows the answer.
Is there another, more easy (or better) way to do this?
More data and information can be given if needed.
Thank you for your help.
EDIT: '...has/is being copied?' changed to pasted as it should've been.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim UndoList As String
'~~> Get the undo List to capture the last action performed by user
UndoList = Application.CommandBars("Standard").Controls("&Undo").List(1)
'~~> Check if the last action was not a paste nor an autofill
If Left(UndoList, 5) = "Paste" Then
'Do stuff
End If
End Sub
This did the trick. For those who need something similar and know the size of their list #MaciejLos' answer would also work.
Worksheet_Change event will do the job if you add a formula into cell which will never be overwritten. Let's say your data are pasted into A1 cell and occupied 5 columns. So, enter below formula into 6. column and row 1.
=COUNTBLANK(A1:A1048576)
Now, you're able to handle/detect paste event ;)
I was unable to add this as a comment so I'm posting this as an answer.
#Nahbyr 's answer works when excel has "English" set as it's preferred language,
otherwise it won't work.
So after manually searching using the immediate window I was able to find out the appropiate indexes for it to work on every language.
This is the function I wrote to test if the last action was a paste action, paste or paste special.
Public Function LastActionPaste() As Boolean
' The function LastActionPaste checks if the last action made was a paste action, if so it returns TRUE
' Otherwise it returns FALSE
Dim UndoList As String
LastActionPaste = False
UndoList = Application.CommandBars(11).Controls(14).List(1)
'~~> Check if the last action was a paste or paste special
If UndoList = "Paste" Or UndoList = "Paste Special" Then
LastActionPaste = True
End If
End Function
UPDATE
So apparently the indexes are not the same on different installations of Excel, whether because they are different versions or whatsoever...
So even if the preferrred language is not English, the CommandBars.Name is still in english, BUT the Controls.Caption do change...
Now I hope that the Controls indexes do not change otherwise this won't work.
So I modified the function like this for it to work:
Public Function LastActionPaste() As Boolean
' The function LastActionPaste checks if the last action made was a paste action, if so it returns TRUE
' Otherwise it returns FALSE
Dim UndoList As String
Dim barFound As Boolean
Dim index As Long
LastActionPaste = False
index = 1
barFound = False
Do While barFound = False
If Application.CommandBars(index).name = "Standard" Then
barFound = True
Else
index = index + 1
End If
Loop
UndoList = Application.CommandBars(index).Controls(14).List(1)
'~~> Check if the last action was a paste or paste special
If UndoList = "Paste" Or UndoList = "Paste Special" Then
LastActionPaste = True
End If
End Function

VBA Formating on Characters greater than 255 using Characters.Font

I posted a question recently on how to format the first part of text from a input box and append it to existing text in a cell.
So for example if I have a cell with... this
23/08/2013: Hi there how are you today
24/08/2013: Customer is feeling good today
and I double click the cell, I get an input box to enter a comment. I take the comment.. add todays date to it in the VBA code and then append and format it to the existing code using this
If Target.Column = NOTES_COL Then 'Add a note
lngPos = Len(Target.Text)
strNote = InputBox(Prompt:="Enter Note", _
Title:="Notes", Default:="")
If (Len(Trim(strNote)) > 0) Then
If Target.Value = "" Then
Target.Font.Bold = False
newVal = Date & ": " & strNote
Else
newVal = Chr(10) & Date & ": " & strNote
End If
Target.Characters(Start:=lngPos + 1).Text = newVal
Target.Characters(Start:=lngPos + 1, Length:=11).Font.Bold = True
End If
End If
So basically this takes a comment... adds a date to the comment, and a new line and then appends it to the existing characters and formats the date Bold.
This all works fine until I go over 255 Characters, which the poster that helped me in the last solution warned about, but I thought it was trying to insert one comment > 255 and not the entire cell lenght.
How do I get around this... as I can add mulitple comments into a cell
regards Mick
A similar issue was discussed on SO here. According to that thread, the issue is that the InputBox method only allows a max of 255 characters. I've verified this myself.
That thread also suggested using a userform. That is the best option, especially considering entering over 255 characters in a one-line inputbox is probably setting up for frustration. How will you review what you've already typed, for example?
There are a few less polished options I can think of:
Have users enter comments directly in another cell - for example, select (and I hate using select!) a different cell, and let the user put whatever notes they desire there. Then run code to append that cell's value to your target cell.
Something even more crazy would be to call an outside program, such as notepad (or the Mac counterpart), save, and import that information in to append to the target cell.
All of these options are just work-arounds for the InputBox limit. Maybe there are some better alternatives someone more experienced can think of?
Update
Also, there seems to be an issue with using .Characters to add to anything over 255 characters long. I suspect this is because the .Characters method (not property) is set up to work on a textframe, not a cell value. A textframe is actually an object that works with shapes. It's interesting you're using it here on a range to edit its value - cool trick, courtesy of another question you've asked.
A solution would be to replace the cell value. You can then use .Characters as an object, to format portions of the cell value, as I think you've already tried to do in your other question.

Office Word: Put a different color for every letter using VBA

I have a doc(docx) file and I want that every letter from every word to have a different color.
Letter a (A) - color red
Letter b (B) - color blue
etc
How can I achieve this?
I hate VBA in office because for some reason they decided not to update VBA like they did when they updated it for visual studio's macro interface...because of compatibility with older documents.... however, i think this should get you started, because of what I said, it should work on just about any version of word that has vba, i put this code inside a new module called "NewMacro" -- if you use office 2010, the macros are accessible via the "View" ribbon on the far right "Macros" panel (just right of the "Window" panel).. then just type the name ColorizeLetter under macro name and click "Create" button and add this code below (the Sub ColorizeLetter() will be put there for you, i just added it here for completeness or if you have an existing module already and know how to do it w/o the macro window). Also, I assume that only one document is open in word at this time, you will need to add functionality if dealing with more than one document, a specific document, (just modify the "Set X = " line to do that)...
Sub ColorizeLetter()
'
' ColorizeLetter Macro
'
'
Dim D As Range
Dim C As Characters
Dim X As Document
Set X = Word.Documents.Item(1)
For I = 1 To X.Words.Count
Set D = X.Words.Item(I)
For J = 1 To D.Characters.Count
S$ = D.Characters.Item(J).Text
Select Case S$
Case "A"
D.Characters.Item(J).Font.ColorIndex = wdRed
Case "B"
D.Characters.Item(J).Font.ColorIndex = wdBlue
End Select
Next
Next
End Sub
Just add in the colors you want for the other chars in the Select Case block and you should be good to go..... hope this helps.