python win32com excel border formatting - python

I have a piece of code here that actually work to format the borders in excel using python win32com. My concern is the time it take to format the borders. I tried to record a macro in excel to find out the required information to transpose it in my script but it didn't work.
So the best that I can do is to run in a for range loop where I always start at row 3 up to a row counter called shn[1] by increment of 1 and from column 1 to 10 by increment of 1. From there I use "BorderAround()" which work fine but too slow. Here my piece of code:
for shn in [("Beam-Beam", bb_row, bb_col), ("Beam-Col", bc_row, bc_col)]:
sheet = book.Worksheets(shn[0])
sheet.Range( "J3:DW3" ).Copy()
if shn[0] == "Beam-Col":
sheet.Range( "J3:AA3" ).Copy()
sheet.Range( sheet.Cells( 4, 10 ), sheet.Cells( shn[1]-1, 10 ) ).PasteSpecial()
for mrow in xrange(3,shn[1],1):
for mcol in xrange(1,10,1):
sheet.Cells(mrow, mcol).BorderAround()#.Border(1)
Is there something I can do to format the borders with a range like ==> sheet.Range( sheet.Cells(3,1), sheet.Cells(shn[1],10) )? I tried ".Borders(11)" and ".Borders(12)" plus ".BorderAround()", but only ".BorderAround()" have worked.
Thanks in advance.

Hmm, what excel are you using?
This should work:
for shn in [("Beam-Beam", bb_row, bb_col), ("Beam-Col", bc_row, bc_col)]:
sheet = book.Worksheets(shn[0])
sheet.Range( "J3:DW3" ).Copy()
if shn[0] == "Beam-Col":
sheet.Range( "J3:AA3" ).Copy()
## Set a variable named rng to the range
rng = sheet.Range( sheet.Cells( 4, 10 ), sheet.Cells( shn[1]-1, 10 ) )
rng.PasteSpecial()
## Using this range, we can now set its borders linestyle and weight
## -> where 7 through 13 correspond to borders for xlEdgeTop,xlEdgeBottom,
## xlEdgeRight, xlEdgeLeft, xlInsideHorizontal, and xlInsideVertical
## -> LineStyle of 1 = xlContinous
## -> Weight of 2 = xlThin
for border_id in xrange(7,13):
rng.Borders(border_id).LineStyle=1
rng.Borders(border_id).Weight=2
## And to finish just call
book.Close(True) # To close book and save
excel_app.Quit() # or some variable name established for the com instance
Let me know how this works for you.
Also it may be faster if you set the excel applications Visible to False or turned off screenupdating:
excel_app.Visible = False # This will not physically open the book
excel_app.ScreenUpdating = False # This will not update the screen on an open book
##
# Do Stuff...
##
# Just make sure when using the ScreenUpdating feature that you reenable it before closing
excel_app.ScreenUpdating = True
This way excel isn't updating the screen for every call.

Related

How to change the LineWidth of a cell border using PyUNO in LibreOffice Calc?

I am writing a Python script to automatically adjust cell borders in LibreOffice Calc. I think I know what property I need to change, however when I assign a new value to this property, the value does not change.
For instance, I wrote this code to change the TopLine.LineWidth of a single Cell from 0 to 10.
# Access the current calc document
model = desktop.getCurrentComponent()
# Access the active sheet
active_sheet = model.CurrentController.ActiveSheet
# Get the cell and change the value of LineWidth
cell = active_sheet.getCellByPosition(2, 2)
cell.TableBorder2.TopLine.LineWidth = 10
I don't get any errors after running this code. And I have also made sure that I am accessing the cell I wish to modify. However, this code does not change the cell's border width.
I tried doing some debugging by printing the value before and after the assignment:
# This first print statement returns 0 because the cell has no borders
print(cell.TableBorder2.TopLine.LineWidth)
cell.TableBorder2.TopLine.LineWidth = 10
# This second print statement still returns 0, but I was expecting it to return 10
print(cell.TableBorder2.TopLine.LineWidth)
Does anyone know what I am doing wrong?
You need to set the cell property to a changed border object. From https://ask.libreoffice.org/en/question/145885/border-macro-no-longer-works/:
aThinBorder = oRange.TopBorder2
aThinBorder.LineWidth = 1
oRange.TopBorder2 = aThinBorder
So, after doing a lot of research, I found at least three methods to change border settings. Because it took me so much effort, I figured I should leave them here so in the future other people may find the answer more easily.
In all examples I'll set the LineWidth of the TopBorder of a single cell to 10.
Method 1: Using getPropertyValue() and setPropertyValue()
cell = active_sheet.getCellByPosition(1, 1)
border_prop = cell.getPropertyValue("TopBorder")
border_prop.LineWidth = 10
cell.setPropertyValue("TopBorder", border_prop)
Method 2 (derived from Jim K's answer)
cell = active_sheet.getCellByPosition(1, 1)
border_prop = cell.TopBorder2
border_prop.LineWidth = 10
cell.TopBorder2 = border_prop
Method 3: Using a BorderLine2 struct
border_prop = uno.createUnoStruct("com.sun.star.table.BorderLine2")
border_prop.LineWidth = 10
cell = active_sheet.getCellByPosition(1, 1)
cell.setPropertyValue("TopBorder", border_prop)

How to use different fonts for two lines within the same cell in Excel?

I have an excel file with a table A6:E233. I had to concatenate columns A and B so that values from B are displayed in a new line. I have achieved that with the CONCATENATE function (and CHAR(10) for new line) that is built into Excel.
After concatenation the spreadsheets looks like this:
EXAMPLE1
Now i would also need different formatting for each line inside the cell, namely size 12, bold for the first line and size 8 for second line:
EXAMPLE2
How do achieve this? If it would be a short table, I would do it manually, but since I have a few files, totally well over 5000 rows, maybe an automated way would be better.
I have found answers that touch upon this problem, but since I dont know how to use VBA, I am more or less lost. I am also using a lot of python and have looked through openpyexl and csv, but have not found a way how to achieve this.
Thank you for your help!
With Excel VBA, you need to use the Characters property of the Range object. For example:
Sub Test()
Dim rngCell As Range
Dim lngPos As Long
'get cell
Set rngCell = Sheet1.Range("A1")
'find linebreak
lngPos = InStr(1, rngCell.Value, vbLf, vbBinaryCompare)
'format either side
rngCell.Characters(1, lngPos).Font.Bold = True
rngCell.Characters(lngPos + 1, Len(rngCell.Value) - lngPos).Font.Color = 1234
End Sub
Which will format like this:
Here, try this code. I built this according to your screenshot.
Sub partialFormatting()
Dim tws As Worksheet
Dim fr, lr As Integer
Dim pos As Integer
Set tws = ThisWorkbook.Worksheets("Sheet1")
fr = 7
lr = tws.Range("A1000000").End(xlUp).Row
For r = fr To lr
With tws.Range("A" & r)
pos = InStr(.Value, vbLf)
With .Characters(Start:=1, Length:=pos - 1).Font
.FontStyle = "Bold"
.Size = 12
End With
With .Characters(Start:=pos + 1, Length:=Len(.Value) - pos).Font
.FontStyle = "Normal"
.Size = 8
End With
End With
Next r
End Sub
Please let me know if you have any questions on how the code works!

dropping an image with win32com (MS WORD)

I am trying to create a series of name badges and rather than doing it all by hand I'm trying to do it via python. I am using the win32com.client approach to create a table in msword to hold each name badge however the images I am inserting into each cell are pushed up against the top of the cell whereas I want them moved down a bit (Image is oversized I know but that can be dealt with later).
As you can see the image is write against the top of the border, I want it pushing down, I have tried adding newlines before (demonstrated below) but this seems to have had no effect. This is my loop for generating the badges.
for i in range(10):
cell_col = i % cols + 1
cell_row = i / cols + 1
cell_range = table.Cell(cell_row, cell_col).Range
cell_range.ParagraphFormat.SpaceBefore = 0
cell_range.ParagraphFormat.SpaceAfter = 3
table.Cell(cell_row, cell_col).Range.InsertBefore('\n')
cell_range.InlineShapes.AddPicture(os.path.join(os.path.abspath("."), filename))
table.Cell(cell_row, cell_col).Range.InsertAfter('\n'+hold[i])
table.Cell(cell_row, cell_col).Height = 150
table.Cell(cell_row, cell_col).Width = 250

Trouble with creaing custom tool in Arcmap

I am trying to create my own tool to use in ArcMap but keep running into a problem. I want to create a buffer (which I can do) and then clip the points that fall within the buffer. The problem I run into is that I cannot figure out how to use the buffer as the input feature for the clip section of my tool.
import arcpy
import os
from arcpyimmport env
env.workspace = "C:/LabData"
arcpy.env.overwriteOutput = True
In_lake = arcpy.GetParameterAsText(0)
Out_Buff = arcpy.GetParameterAsText(1)
Buffer_Distance = arcpy.GetParameterAstext(2)
in_cities = arcpy.GetParameterAsText(3)
cliped_cities = GetParameterAsText(4)
New_Table = arcpy.GetParameterAsText(5)
Join_Input = arcpy.GetParameteAsText(6)
# step 1 create a buffer around the lakes
arcpy.Buffer_analysis(In_Lake, Out_Buff, Buffer_Distance)
# Step 2 Clip all cities that fall within the buffer
arcpy.Clip_analysis( in_cities,out_Buff, clipped_cities)
# Step 3
arcpy.Statistics_analysis(clipped_cities, New_Table, statistics_fields,\
'Population SUM', 'CNTRY_NAME')
# Step 5
arcpy.AddField_management (New_Table, 'Country', 'TEXT')
]1
Check carefully that your variable names match -- Python and ArcPy are case sensitive.
In_Lake = arcpy.GetParameterAsText(0) ## was In_lake
Out_Buff = arcpy.GetParameterAsText(1)
Buffer_Distance = arcpy.GetParameterAstext(2)
in_cities = arcpy.GetParameterAsText(3)
clipped_cities = GetParameterAsText(4) ## was cliped_cities
New_Table = arcpy.GetParameterAsText(5)
Join_Input = arcpy.GetParameteAsText(6)
# step 1 create a buffer around the lakes
arcpy.Buffer_analysis(In_Lake, Out_Buff, Buffer_Distance)
# Step 2 Clip all cities that fall within the buffer
arcpy.Clip_analysis(in_cities, Out_Buff, clipped_cities) ## was out_Buff
Unless you want to keep the lake buffer, it doesn't necessarily need to be an input parameter specified by the user. Consider instead using the in_memory workspace -- just be aware any data in it will be deleted once the tool execution is completed.
Out_Buff = r'in_memory\lakeBuffer'
A similar strategy can be used for any intermediate feature class or table that you don't really care about. However, it's sometimes useful to have those intermediate results around to verify that your tool is doing what you expect at every step.

Erasing only a part of an excel with win32com and python

I have 3 parameters.
startLine, starColumn and width (here 2,8,3)
How can I erase the selected area without writing blanks in each cells?
(here there is only 30 line but there could potetialy be 10 000 lines)
Right now I'm succesfully counting the number of lines but I can't manage to find how to select and delete an area
self.startLine = 2
self.startColumn = 8
self.width = 8
self.xl = client.Dispatch("Excel.Application")
self.xl.Visible = 1
self.xl.ScreenUpdating = False
self.worksheet = self.xl.Workbooks.Open("c:\test.xls")
sheet = self.xl.Sheets("data")
#Count the number of line of the record
nb = 0
while sheet.Cells(start_line + nb, self.startColumn).Value is not None:
nb += 1
#must select from StartLine,startColumn to startcolum+width,nb
#and then erase
self.worksheet.Save()
ps : the code works, I may have forgotten some part due do copy/pas error, in reality the handling of the excel file is managed by several classes inheriting from each other
thanks
What I usually do is that I record macro in Excel and than try to re-hack the VB in Python. For deleting content I got something like this, should not be hard to convert it to Python:
Range("H5:J26").Select
Selection.ClearContents
In Python it should be something like:
self.xl.Range("H5:J26").Select()
self.xl.Selection.ClearContents()
Working example:
from win32com.client.gencache import EnsureDispatch
exc = EnsureDispatch("Excel.Application")
exc.Visible = 1
exc.Workbooks.Open(r"f:\Python\Examples\test.xls")
exc.Sheets("data").Select()
exc.Range("H5:J26").Select()
exc.Selection.ClearContents()
this worked for me
xl = EnsureDispatch('Excel.Application')
wb2=xl.Workbooks.Open(file)
ws=wb2.Worksheets("data")
ws.Range("A12:B20").ClearContents()

Categories