How to unlock column widths and row heights in openpyxl - openpyxl

I have an excel file.
I needed to lock the first column.
To achieve this in openpyxl, I locked the entire sheet using ws.protection.sheet = True and unlocked the columns mentioned above.
However, locking the entire sheet also prevents users from resizing the columns or row widths and heights.
It is not possible to do Protection(locked=False) because it only works on rows and columns with indices >= 1.
The code to lock the columns is written below:
ws.protection.sheet = True
for i in range(1, max_row + 1):
ws.cell(row=i, column=1).protection = Protection(locked=True)
Any advices?

To allow resizing of the columns and rows
After
ws.protection.sheet = True
The following are set to True so need to change to False
ws.protection.formatColumns = False
ws.protection.formatRows = False

Related

Query returning 1st cell in range although condition is not met (Google Sheets)

I'm a first time query-user, so I'm out of my depth for fixing this myself.
Here's what I have and am looking to accomplish in two separate Google Sheets spreadsheets:
Spreadsheet1 - column A contains a list of names, column B contains a checkbox for true or false
Spreadsheet2 - import list of names from Spreadsheet1 column A where column B is true (and transpose the names so they appear in columns)
This is the formula I'm using in Spreadsheet2:
=TRANSPOSE(QUERY(IMPORTRANGE(LinkToSpreadsheet1,"Sheet1!A39:B51"),"Select Col1 where Col2 = TRUE",1))
The problem I'm facing is:
When column B in Spreadsheet1 contains only FALSE results, the formula is still returning cell A39 as the result, rather than returning no result.
I've also tested that when column B in Spreadsheet1 does contain a TRUE result (for example cell B48 = TRUE), but A39 is FALSE -- it is still returning cell A39 in addition to the matching TRUE cell of A48.
The problem I'm facing is:
When column B in Spreadsheet1 contains only FALSE results, the formula is still >returning cell A39 as the result, rather than returning no result.
that's because you use 1 as 3rd query parameter. you should use 0. try:
=IFERROR(TRANSPOSE(QUERY(IMPORTRANGE(LinkToSpreadsheet1,"Sheet1!A39:B51"),
"select Col1 where Col2 = TRUE", 0)))

How to code button to hide a range of cells?

I am trying to create buttons that imitate the nature of nested rows, where when clicked, will hide the indented columns below it. I previously targeted a specific range of rows for each button, but as my company will attempt to add rows in the future, I want the code to continue to run properly regardless of where in the sheet the new row is added. Below is the code that I used:
Sub aButton()
With Rows("1:22")
If .Hidden Then
.Hidden = False
Else
.Hidden = True
End If
End With
End Sub
My attempted work around is to make a hidden column with A, B, C values per row to identify which range of rows go together. I want to be able to target all rows with "A" in column G, and use those values as my range in my existing code.
Can you help?

Macro to Hide/Unhide Columns in Excel

I created a simple macro to hide/unhide columns in Excel (attached below).
It works fine, however, when adding a column within the range of columns in the macro, the last column supposed to be hidden remains unhidden.
To make myself clear: The range of columns in macro is AM:BF. When I need to add a column within this range, the column BF stays unhidden. Could you help me how to improve the code so that the initial range of columns would stay hidden as well as the added one?
With Columns("AM:BF")
If .EntireColumn.Hidden = True Then
.EntireColumn.Hidden = False
Else
.EntireColumn.Hidden = True
End If
End With
You need to have a placer for the column. You could used a named range along the top row of columns AM:BF (Which will then change if you add a column in the middle of it). Your code could then look like
With ThisWorkbook.Sheets("MySheet").Range("NamedRange").EntireColumn
.Hidden = Not .Hidden
End With

I want to hide a column in excel using VBA macro in run time but while executing other columns also get selected.

I want to hide column C based on value in cell AB7.
If value in cell AB7 is 117 then entire column C needs to hide.
Else I want column C to be there.
If Range("AB7").Value = "117" Then
Columns("C:C").Select
Selection.EntireColumn.Hidden = True
Else
Columns("C:C").EntireColumn.Hidden = False
End If
When I run the code columns A:G also get selected. Please let me know if there are any limitations while using the above code. I use excel 2010. Thanks in advance.
I would recommend not using select. Columns("C:C").Hidden = False and Columns("C:C").Hidden = True

(Excel 2003 VBA) Delete entire rows based on multiple conditions in a column

I have an interesting issue. I've tried searching this site and Google but there are only slightly related problems, none which actually address this specific need.
I have a spreadsheet with 10 columns (let's call them A-J). I need to delete all the rows that do NOT have a value of "30", "60", "90", "120" or blank within the cells of column H.
Though there are many ways of doing this, all of them have relied on loops, which doesn't work for me as this dataset has over 25k rows and it takes 10+ minutes to run - too long.
I've been looking at autofilter options in conjunction with the .Find function (e.g. find all rows with H cells that don't meet the criteria and delete) but AutoFilter on 2003 only works with 2 criteria, while I have 5 to check against. I'm not sure how to proceed.
Any help is appreciated.
This deleted all matching rows (~10%) in a sample of 25k rows in 20sec
Sub tt()
Dim rw As Range
Dim all As Range
Dim t
Dim b As Boolean
t = Timer
For Each rw In Range("A1").CurrentRegion.Rows
If rw.Cells(8).Value < 1 Then
If b Then
Set all = Application.Union(rw, all)
Else
Set all = rw
b = True
End If
End If
Next rw
If not all is nothing then all.EntireRow.Delete
Debug.Print "elapsed: " & Timer - t
End Sub
You can try Advanced Filter option where you can give more than two criteria to filter the list. After filtering the list matching the criteria you set, the filtered list can be copied to another location (option available) and the remaining deleted.
You can add a column with the condition of your own:
=IF(OR(H1=30;H1=60;H1=90;H1=120;H1="");"DELETE";"")
(the formula is given for row 1, you have to copy-paste it to the entire range)
Then use filtering and sorting to select the rows to delete.
Some speed tips:
When using large data, assign values to array and use array instead of *.Value;
When working with full columns, ignore empty columns at bottom;
When making intensive changes in worksheet, disable screen update and automatic calculation.
Stating this, I would use this code:
Sub Macro1()
Dim su As Boolean, cm As XlCalculation
Dim r As Long, v(), r_offset As Long
su = Application.ScreenUpdating
Application.ScreenUpdating = False 'Disable screen updating
cm = Application.Calculation
Application.Calculation = xlCalculationManual 'Disable automatic calculation
'Only use used values
With Intersect(Range("H:H"), Range("H:H").Worksheet.UsedRange)
v = .Value 'Assign values to array
r_offset = .Row - LBound(v) 'Mapping between array first index and worksheet row number
End With
'Check all row from bottom (so don't need to deal with row number changes after deletion)
For r = UBound(v) To LBound(v) Step -1
Select Case v(r, 1)
Case "30", "60", "90", "120", Empty 'Do nothing
Case Else
Sheet1.Rows(r + r_offset).EntireRow.Delete
End Select
Next
Application.ScreenUpdating = su 'Restore screen updating
Application.Calculation = cm 'Restore calculation mode
End Sub
Thanks to all who've suggested solutions. In the between time I ended up figuring out a way to do this in <1 second - apparently I myself didn't realise that AutoFilter could've supported comparison criteria (greater than, less than etc).
Using a series of autofilters I simply filtered for, then deleted all rows that filtered to "<30", "30120".
Not elegant, but it did the trick.