I am trying to automate the preparation of an internal Excel-based report based on a previous template.
The macro creates and fills a new sheet, matching the font name, size, color etc. settings of the template, as well as the row heights - column widths. Despite providing the exact same values for font, height, width etc., the VBA produced sheet's font does not match the original template. I believe the issue can be fixed if we can figure out why the VBA produced text is "pixelated".
As I am not familiar with the file sharing best-practices of SO, I will be including code used to reproduce the new sheet and a comparison of some attributes of the both sheets. I will include a link to the file containing the two sheets in the comments. I believe it may be important to have a copy of the original template to answer this question.
Here is an example of how a cell's properties are changed, pretty basic.
ws.Columns(12).EntireColumn.ColumnWidth = 9.57
ws.Rows(9).EntireRow.RowHeight = 50.25
ws.Cells(9, 12).Font.Name = "Segoe UI"
ws.Cells(9, 12).Font.Size = 11
Here are some properties I compared for the two sheets as I did not know what I was looking for, all are identical for the two sheets.
Range.AddIndent = False
Range.ColumnWidth = 9.57
Range.RowHeight = 50.25
Range.Font.Name = "Segoe UI"
Range.Font.FontStyle = "Regular"
Range.Font.Size = 11
Range.Font.ThemeFont = xlThemeFontNone
Range.Font.ThemeColor = 2
Range.Font.OutlineFont = False
Range.Font.Subscript = False
Range.Font.Superscript = False
Range.Font.Italic = False
Range.HasSpill = False
Range.Phonetics = Nothing
Range.PrefixCharacter = ""
Range.SpillingToRange = Nothing
Range.UseStandardHeight = True
Range.UseStandardWidth = False
Range.WrapText = True
Worksheet.Cells.AddIndent = False
Worksheet.EnableOutlining = False
Worksheet.Outline.AutomaticStyles = False
Worksheet.PageSetup.BottomMargin = 18 'These are different, but did not effect the outcome when equalized
Worksheet.PageSetup.LeftMargin = 50.4 'These are different, but did not effect the outcome when equalized
Worksheet.PageSetup.FooterMargin = 21.6 'These are equal for both
Worksheet.PageSetup.HeaderMargin = 21.6 'These are equal for both
Worksheet.StandardHeight = 16.5 'These are different, yet read-only
Worksheet.StandardWidth = 8.38 'These are different, yet read-only
I know a little HTML/CSS and my guess is despite having the same font families(names), the .woff2 or .eot are different for the two fonts. I have no idea why though.
Painting the target cells using the original template format does the job, as does a copy/pasting strategy, but I am aiming for a clean solution without including the template in the final file and generating the sheets from scratch. I could also change the font family or cell sizes to get an acceptable output, but at this point I wish to explore the reason behind this issue out of curiosity.
Related
My Excel macro reads the answers to a survey from a set of Excel files. The answers of a survey contain a score (from 1 to 4) and a description. The goal is to generate a a matrix. Each cell of the matrix has a color that represents the score. I would like the user to be able to modify the layout of these cell. To make it easy to the user, I created a template matrix and a button. The user should be able to modify the layout of the cells and on a click of a button, a set of styles (Score 1, Score 2,...) should be generated. Once the matrix is created, the Workbook should be to function without the survey files.
I have tried a couple of things:
Try 1
ThisWorkbook.Styles.Add "Score 1", BasedOn:=cell1
This gives errors. I don't fully understand when they occur, but one of the causes is when the user modifies the cell layout by selecting another style.
Try 2
ThisWorkbook.Styles("Score 1").Delete
ThisWorkbook.Styles.Add "Score 1", BasedOn:=cell1
This is not a good idea: all cells loose their styling when it is executed a second time.
Try 3: Current
Copy the most frequently used properties of the cells layout and copy them to the style. If this style is deleted by the user, it is recreated. This procedures is not ideal, since most style properties won't be covered.
Is there a way to update a cell style that is more general? I would like there to be as little room as possible to make the workbook in an inconsistent and non-functional state.
I sticked with try 3. Because it required a lot of code for all properties that seemed possible to be edited, and because of copying borders is tricky, I post the result.
'xR1_Template: the cell to base the style on
'nm_Style: the name of the style
Public Function Upsert_Style(xR1_Template As Excel.Range, nm_Style As String) As Excel.Style
Dim xStyle As Excel.Style
Set xStyle = Fn.TryGet(ThisWorkbook.Styles, nm_Style)
If Fn.IsNothing(xStyle) Then
Set xStyle = ThisWorkbook.Styles.Add(nm_Style)
End If
xStyle.Font.Color = xR1_Template.Font.Color
xStyle.Font.Bold = xR1_Template.Font.Bold
xStyle.Font.Name = xR1_Template.Font.Name
xStyle.Font.Italic = xR1_Template.Font.Italic
xStyle.Font.Size = xR1_Template.Font.Size
xStyle.Font.Strikethrough = xR1_Template.Font.Strikethrough
xStyle.Font.Subscript = xR1_Template.Font.Subscript
xStyle.Font.Superscript = xR1_Template.Font.Superscript
xStyle.Font.Underline = xR1_Template.Font.Underline
xStyle.Interior.Color = xR1_Template.Interior.Color
xStyle.Interior.Pattern = xR1_Template.Interior.Pattern
xStyle.Interior.PatternColor = xR1_Template.Interior.PatternColor
'NOTE: necessary to delete all borders first. There's no way to delete them one by one.
xStyle.Borders.LineStyle = xlNone
Dim iBorder As Long
For iBorder = 1 To xR1_Template.Borders.Count
Dim xBorder As Excel.Border
'NOTE: The Borders property claims to work with xlBordersIndex argument, but this is not true.
' Normal indexing is used.
Set xBorder = xR1_Template.Borders(iBorder)
'NOTE: "none-style" borders (=no border), should be skipped.
' Once they are retrieved using the Borders property, they are always visible.
' Setting them with xlLineStyle.xlLineStyleNone does not hide them.
If xBorder.LineStyle <> XlLineStyle.xlLineStyleNone Then
Dim xBorder_Style As Excel.Border
Set xBorder_Style = xStyle.Borders(iBorder)
xBorder_Style.Color = xBorder.Color
xBorder_Style.LineStyle = xBorder.LineStyle
xBorder_Style.Weight = xBorder.Weight
End If
Next iBorder
xStyle.AddIndent = xR1_Template.AddIndent
xStyle.FormulaHidden = xR1_Template.FormulaHidden
xStyle.HorizontalAlignment = xR1_Template.HorizontalAlignment
xStyle.IndentLevel = xR1_Template.IndentLevel
xStyle.NumberFormat = xR1_Template.NumberFormat
xStyle.NumberFormatLocal = xR1_Template.NumberFormatLocal
xStyle.Orientation = xR1_Template.Orientation
xStyle.ShrinkToFit = xR1_Template.ShrinkToFit
xStyle.VerticalAlignment = xR1_Template.VerticalAlignment
xStyle.WrapText = xR1_Template.WrapText
xStyle.IndentLevel = xR1_Template.IndentLevel
Set Upsert_Style = xStyle
End Function
I have word document with different styles like heading1, heading2, normal, bodytext etc. I'm trying to write a VBA macro which will first modify the styles as per requirement and then apply those styles across the document accordingly. See below, I'm changing the font size first for style=normal and heding1 and then want to apply it for all paragraphs where style=normal is already defined. So it will update the style for existing heading1 and normal separately.
NOTE: I want to do it with style only. I can do it using for loop by going each paragraph one by one and then find what is the style of that paragraph and then apply the style accordingly AND it is working perfectly if I do in this way but in my document I have 60000 paragraphs and so it is taking long time like 10 hours. So, Im looking for a way to do it for each different styles in one shot. Please let me know if there is any way to do it.
ActiveDocument.Styles(wdStyleNormal).Font.Name = "Arial"
ActiveDocument.Styles(wdStyleNormal).Font.Size = 12
ActiveDocument.Styles(wdStyleHeading1).Font.Name = "Arial"
ActiveDocument.Styles(wdStyleHeading1).Font.Size = 20
ActiveDocument.UpdateStyles
I have tried and ended up with this solution. I hope it will work for you.
Sub ChangeStyle()
With ActiveDocument.Styles("wdStyleNormal").Font
.Color = wdColorAqua 'wdColorRed
.Name = "Arial"
.Size = 12
End With
With ActiveDocument.Styles("wdStyleNormal")
.AutomaticallyUpdate = True
End With
End Sub
I've looked over the Openpyxl docs, styles, cell module, and source code, but I'm not seeing what I need. Maybe I missed it (as new to Python).
I need to format certain cells within a spreadsheet(ss) differently from the rest of the ss. Am I able to specify an individual cell as shrink-to-fit, align right, align bottom, font color = grey, etc., while keeping the rest of the SS in the original style? Is this a Cell style that should be set or is there another resource to see what attributes Openpyxl will allow on an individual cells?
Here's a code snippet where the 'al' variable is working, but not the 'br', and I don't know why.
# Cell Alignment
al = Alignment(horizontal='center', vertical='center')
br = Alignment(horizontal='right', vertical='bottom')
for row in sheet['A1':'I43']:
for cell in row:
if cell == 'Hz':
cell.alignment = br #Help: not working
else:
cell.alignment = al
Thanks,
Phil
Ok, I think I've got it. So far, I'm accomplishing individual cell formatting using the NamedStyle object.
Here is my code:
# Set 'Named Styles', which are mutable, when need to apply formatting to different cells at once
headerrows = NamedStyle(name='headerrows')
headerrows.font = Font(bold=True, underline='none', sz=12)
headerrows.alignment = al
rooms = NamedStyle(name="rooms")
rooms.font = Font(bold=True, size=12)
rooms.border = Border(left=bold, top=bold, right=bold, bottom=bold)
sheet['A1'].style = rooms
sheet['A2'].style = headerrows
sheet['A3'].style = 'headerrows'
sheet['A4'].style = 'rooms'
I'm creating a series of tags in Illustrator, using VBA in excel (the excel worksheet has the information that populates the tags), and I cannot find a way to specify that the font which appears in Illustrator is italicized and a particular font.
Using:
.TextRange.CharacterAttributes.TextFont = appIll.TextFonts.Item("Arial")
lends the same result as using:
.TextRange.CharacterAttributes.TextFont = appIll.TextFonts.Item("Monotype Corsiva")
And needless to say, I also can't get italics. I'm very new to this, but would appreciate anyone letting me know how to specify the font and font-style. Thanks!
.TextRange.ParagraphAttributes.Justification = aiCenter
.TextRange.CharacterAttributes.size = dblTopLine1FontSize
.TextRange.CharacterAttributes.StrokeWeight = 0.35
.TextRange.CharacterAttributes.StrokeColor = clrStrokeColor
.TextRange.CharacterAttributes.FillColor = clrFontFillColor
SetItalics tfrmTopLine1
.CreateOutline
End With
have a look at the following to see if it helps:
Firstly, at the risk of stating the obvious, I first identified that the font I 'needed' to use was indeed accessible to my copy of Illustrator - as it happens, to use Monotype Corsiva in code it has to be "MonotypeCorsiva"! The lessons here are that the 'real' font name may be different from the Illustrator displayed font name and the 'real' font name also indicates the 'style'. I used the following code which simply listed the font and its 'style' to Excel's Immediate Window. Illustrator needs to be open for this example.
Sub IllFnts()
Dim IApp As New Illustrator.Application
Set IApp = GetObject(, "Illustrator.Application")
Dim fnt As Illustrator.TextFont
For Each fnt In IApp.TextFonts
Debug.Print fnt.Name & " - " & fnt.Style
Next
End Sub
I then added a Point Text Frame, added some text and changed the TextFont with the code below:
EDIT - UPDATE TO INCLUDE A MEANS OF APPLYING ITALIC
Sub TestChngeFnt()
Dim IApp As New Illustrator.Application
If IApp Is Nothing Then
Set IApp = CreateObject("Illustrator.Application")
Else
Set IApp = GetObject(, "Illustrator.Application")
End If
Dim fnt As Illustrator.TextFont
'A distinctive font for reference?
Set fnt = IApp.TextFonts("Algerian")
'Add a Document
Set docRef = IApp.Documents.Add()
'Add some Point Text
Set pointTextRef = docRef.TextFrames.Add()
pointTextRef.Contents = "Some Text in a Point TextFrame"
pointTextRef.Top = 700
pointTextRef.Left = 20
pointTextRef.Selected = True
pointTextRef.TextRange.CharacterAttributes.Size = 35
IApp.Redraw
'Set distinctive font
IApp.Documents(1).TextFrames(1).TextRange.CharacterAttributes.TextFont = IApp.TextFonts.Item(fnt.Name)
MsgBox "Have a look at the text font before changing to another."
'set a new font to 'regular'
Set fnt = IApp.TextFonts("BodoniMT")
IApp.Documents(1).TextFrames(1).TextRange.CharacterAttributes.TextFont = IApp.TextFonts.Item(fnt.Name)
MsgBox "New text font before changing to italics."
'set font to 'italics' within the same font family?
Set fnt = IApp.TextFonts("BodoniMT-Italic")
IApp.Documents(1).TextFrames(1).TextRange.CharacterAttributes.TextFont = IApp.TextFonts.Item(fnt.Name)
End Sub
This example includes a couple of message boxes to pause the code to observe the text changes.
Applying 'italic' in this example is really selecting a font from the same font family designed as italic? Not completely sure if this is the 'correct' approach with Illustrator or just a workaround,but it may take you forward a little.
You may also find this Adobe Illustrator CS5 Scripting Reference: vbScript useful although the Object Browser in Excel is also a good starting reference.
I know this is very basic, but I have been using Python for 2 weeks now and banging my head against the wall trying to fix this. I have checked almost every single thread in here and tried to make sense of the Python 2.7 documentation and also researched whatever excerpts from Programming with Win32 by Hammod I could find.
Below is a section of my code. I am pulling in a named range from excel into a Python Gui. The data comes into row=4, column=1 as I coded it. The problem is I need to parse this named range so that the range (which is four float points) is split amongst row=4 clomuns 1,2,3,4. I know this is basic. I wouldnt have posted if I could find the answer anywhere else. If someone could just point me in the right direction i would really appreciate it.
xl = win32com.client.Dispatch('excel.application')
wbs = xl.Workbooks
wb = wbs.Open('C:\Users\Owner\Desktop\AutoPrime.xls')
xl.visible = 1
xlSheet = xl.Sheets(1)
xlSheet.Range('Fronts').Value
#Frame
Ftreas = Frame(F, relief="groove", border=2)
Ftreas.pack(side="left")
lp2a = Label(Ftreas, text=xl.ActiveSheet.Range('Fronts').Value, justify='center')
lp2a.grid(row=4,column=1, sticky='EW')
While I have not worked with Phyton before, I know that your line xlSheet.Range('Fronts') will return a Range object. You can access individual cells of a Range object with the default property, e.g.:
rng = xlSheet.Range('Fronts')
val1 = rng(1, 1).Value
val2 = rng(2, 1).Value //this returns the cell in row 2/column 1 of the range
arr = rng.Cells //this will return a 4x1 array of values