In Visual Basic for Applications (VBA), to change a color on the color palette (which applies only to the workbook), you do the following:
ActiveWorkbook.Colors(33) = RGB(6, 8, 242)
ActiveSheet.Range("A1").Font.ColorIndex = 33 'Assign the new colorOnce you set the color of a particular spot on the palette (33) to the best of your ability to the RGB color of your choice
{6 ,8, 242}, you can now set the color of any text or fill to that color by accessing its number
33 color index. This tends to work better than trying to set the color of any font or other object.
However, when you see the Colors property in VBA, you know that you have to find another way, or an approximation in AppleScript. There is no equivalent of the Colors Collection object, and colors cannot be elements because you can't make or delete any colors. The number of colors is fixed at 56.
What you can do is call the command reset colors, which restores the color palette to the defaults. And you can try setting the color property by (RGB) color, but most likely that just chooses one the 56 colors. So you might as well do it using the color index property so that at least you know which color you'll be getting reliably. Call the reset colors command first if you want to be sure of it.
It is also possible to blend colors on occasion. The example below blends two colors in anything that has a pattern or gradient, like a cell interior, or chart or drawing object fill gradient color.
Background format
Background colors and patterns are set using the cell's interior object property:
With ActiveSheet.Range("A1").Interior
.ColorIndex = 3
.Pattern = xlGray50
.PatternColorIndex = 13
End WithIn AppleScript:
tell application "Microsoft Excel" tell interior object of range "A1" of active sheet set color index to 3 set pattern to pattern gray 50 set pattern color index to 13 end tell end tell
This allows you to superimpose a fine-grained pattern (if you want) with its own color over the basic interior color to get a very wide variety of blended colors.
Borders
You can get every border in AppleScript, but it requires more code than in VBA if you need to get all of them at once.
In VBA, borders are an integral part of the object model and are set using the cell's Borders Collection and Border objects. You can set all of the (outside) borders at once using the collection properties:
With ActiveSheet.Range("D10").Borders
.LineStyle = xlDouble
.ColorIndex = 3
End WithOr, you can set borders individually, which is much more analogous in AppleScript.
Borders could not be implemented as elements of range or other objects, though it seems they could be in the sense that they have a many-to-one relationship with the object they're bordering. But they cannot be elements because they are somewhat read-only in that you cannot make new borders or delete existing ones.
You can change their properties, so they are "writable" in that sense. For anything defined as an element, you may want to
make new border at range, but you can't do that, or delete any. Borders are just there.
You also can't use a single border property with enumerated constants for the different types. Borders need to be fully-fledged objects whose properties you can modify: collection object types. AppleScript does not have those. AppleScript doesn't fit built-in, read-only elements into its model. These are dealt with in VBA as collection objects, but become orphans in AppleScript, with no parent aside from base object in AppleScript. The same issue exists with headers and footers in Microsoft Word.
In both cases, you have to do the same thing — only, unlike headers and footers, there are more than six borders. There are 12. You have to use the command get border and specify which border, 12 times, to retrieve each of the 12 borders separately. Word manages borders the same way.
Here is how you have to do it if you want to set the line style and color index of all borders of a cell or range, as in the VBA snippet above:
tell application "Microsoft Excel"
tell range "D10" of active sheet
set allBorders to {} -- initialize a list
set end of allBorders to get border ¬
which border border bottom
set end of allBorders to get border ¬
which border border left
set end of allBorders to get border ¬
which border border right
set end of allBorders to get border ¬
which border border top
set end of allBorders to get border ¬
which border diagonal down
set end of allBorders to get border ¬
which border diagonal up
set end of allBorders to get border ¬
which border edgebottom
set end of allBorders to get border ¬
which border edge left
set end of allBorders to get border ¬
which border edge right
set end of allBorders to get border ¬
which border edge top
set end of allBorders to get border ¬
which border inside horizontal
set end of allBorders to get border ¬
which border inside vertical
end tell
repeat with thisBorder in allBorders
try
set line style of thisBorder to double
end try
try
set color index of thisBorder to 3
end try
end repeat
end tellIn this case, you set the end of a list to each new border, which is a more efficient way of building a list than concatenating lists. It makes no discernible difference when you've just got just one or a few items to process, but if you have to repeat this whole procedure hundreds of times over, it could make a significant difference to the speed of the script.
You can't set the line style (nor any other property) of the whole list at once. The script errors, even if you can exclude any nonexistent borders. So you have to run a
repeat
loop on each member of the list, using
try/end try
for each border. In the case of a standard default worksheet cell, both commands error on the last two borders (inside horizontal and inside vertical), which may mean that they don't really exist, although some object is returned from the get border command each time.
Since you can't run a command (set line style, etc.) on the whole list at once, there isn't much advantage in having the list. You could instead set the line style and color index for each border as you make it, sending each border out to a handler to be processed, like this:
tell application "Microsoft Excel" tell range "D10" of active sheet set thisBorder to get border ¬ which border border bottom my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border border left my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border border right my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border border top my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border diagonaldown my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border diagonal up my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border edge bottom my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border edge left my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border edge right my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border edge top my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border inside horizontal my ModifyBorder(thisBorder) set thisBorder to get border ¬ which border inside vertical my ModifyBorder(thisBorder) end tell end tell on ModifyBorder(thisBorder) tell application "Microsoft Excel" try set line style of thisBorder to double end try try set color index of thisBorder to 3 end try end tell return end ModifyBorder
This is actually more efficient. Either method works well. You need change only the commands, in the
ModifyBorder
handler or in the
repeat
loop of the first method, to apply different effects to all of your borders.
Most of the time you will be setting properties of just one, or a few, borders. Here is what the VBA version might look like:
With ActiveSheet.Range("D10")
.Borders.LineStyle = xlNone ' Remove existing borders
With .Borders(xlEdgeLeft)
.LineStyle = xlContinuous
.Weight = xlThin
.ColorIndex = 3
End With
With .Borders(xlEdgeRight)
.LineStyle = xlContinuous
.Weight = xlThick
.ColorIndex = 3
End With
End WithTo remove all existing borders, run either sequence above, but change the commands in the
repeat
loop or
ModifyBorder
handler to:
set line style of thisBorder to line style none
Then follow with:
tell application "Microsoft Excel" tell range "D10" of active sheet set thisBorder to get border ¬ which border edge left tell thisBorder set line style to continuous set weight to border weight thick set color index to 3 end tell set thisBorder to get border ¬ which border edge right tell thisBorder set line style to continuous set weight to border weight thick set color index to 3 end tell end tell end tell
Since you are making the same three settings to each of the two edge borders, again it would be better practice to use a handler to customize the operation:
tell application "Microsoft Excel" tell range "D10" of active sheet set thisBorder to get border ¬ which border edge left my Customize(thisBorder) set thisBorder to get border ¬ which border edge right my Customize(thisBorder) end tell end tell on Customize(thisBorder) tell application "Microsoft Excel" tell thisBorder set line style to continuous set weight to border weight thick set color index to 3 end tell end tell end Customize
You will notice that it is possible to send an application object out to an external handler as a parameter even though that takes it outside of the Microsoft Excel
application block. The handler can still accept the item (which it will know as
border id border
edge left of cell "D10" of active sheet of application
"Microsoft Excel") to pass back into the application
tell
block within the handler when called.


