Openpyxl update Data Validation - openpyxl

I want to create a drop down list in a excel sheet, and be able to update it when I load this sheet. When I change the items in my DataValidation list, and add it to the sheet, the list doesn't change.
Is there a way to update my list or just delete it?
wb = openpyxl.load_workbook(path)
ws_meteo = wb.active
dv = DataValidation(type="list", formula1=Formule, allow_blank=True)
dv.add_cell(ws_meteo['A10'])
ws_meteo.add_data_validation(dv)
wb.save(path)

Being five years late. I think I've encountered the same issue you did.
I have a excel file which needs unique data validation list for individual cells based on an external web service. This works fine when there is no data validation present in the cell. However if a data validation list is present, it appends another data validation list to the cell. On opening the file in Excel, It appears to select the first data validation list it encounters, thus the dropdown list never changes.
I solved it by removing any existing data validation for that cell before adding the new one. I used the following code.
def removeExistingCellDataValidation(worksheet, cell):
toRemove = []
# Append all validation rules for cell to be removed.
for validation in worksheet.data_validations.dataValidation:
if validation.__contains__(cell):
toRemove.append(validation)
# Process all data validation rules set for removal.
for rmValidation in toRemove:
worksheet.data_validations.dataValidation.remove(rmValidation)
After clearing the existing data validation I add the new data validation list as usual, the same way you do in your code snippet.

Related

ActiveX Combobox value not setting to linkedcell on another sheet on workbook_open

We have created a workbook which use ActiveX objects and macros to perform multiple actions (calculations, changing values in cells, forcing mandatory fields before save, colour changes, lock and unlock, etc). There are 3 sheets:
Lists - where we set the values for comboboxes, run mandatory checks against cells and comboboxes, etc. this is VeryHidden to the user
Form - this is where the user will enter their data. it contains all of the ActiveX objects
Import - this is a formatted sheet which we can import to our database with expected formatting on values (i.e. "inches" instead of "in.H2O#60F", days converted to hours). this sheet is VeryHidden.
This workbook can be downloaded blank from our website and imported back into the database successfully.
What we want to do is download a pre-populated version where "Form" shows data from the database. To do this we are populating the Import sheet with the values (as they are already linked to the comboboxes we need to populate). i.e. ComboA on "Form" is linked to cell A4 on "Import".
We expected the comboboxes with linked cells to the update when we downloaded and opened the pre-populated workbook. When it did not we tried:
Sheets("Import").EnableCalculation = False
Sheets("Import").EnableCalculation = True
Application.Calculate
to force the row to "recalculate" and therefore trigger the linked cell to work as when we manually went into one of the linked cells and pressed enter (or F9) the associated combobox updated.
This was partially successful in that is populated around 1/3 of the comboboxes but not all of them. There does not seem to be an order or data type causing the issue (some Y/N update, others do not. comboboxes A-D will update, then E-G will not, then H will).
We tried Application.CalculateFull as well as:
setting the linkedcells to Dirty
only applying .Calculate to the range on the worksheet
only applying .Calculate to the row on the worksheet (as it is all in one row)
We can manually force each combobox to populate with it's linked cell however given the number of comboboxes and the fact there will be more workbooks like this to build this is not an ideal solution.
We know it is hitting the workbook_Open() event as we put in some MsgBox items and the couple custom populations we do (converting degF to F then pushing to combobox) and that is working fine.
If we open the download, save it (skipping the mandatory fields before save), then reopen it everything populates/selects correctly (which is all the more frustrating).
Any thoughts on why the downloaded version is not acting as expected would be much appreciated.
given the other posts I have seen and the follow up information requested I though more was better. there is a code snippet there - and we found a solution to the issue. needed to add Application.Calculation = xlCalculationAutomatic to the open event before the code provided above. thanks anyways

Excel VBA - Pull information into user form to update

I am trying to create a userform that allows the users to update issues stored in a specific sheet (called Issues List). I have built a dropdown list using data validation that allows the user to select the unique issue name from a list. I have created a button next to that dropdown which opens up the userform and correctly imports the issue name identified from the dropdown.
What I need to figure out is, when the user form is initiated how do I have it search column B in my Issues List sheet and identify which row contains the issue selected by the user, and populate the fields of the user form with the information found in rows C-X of the Issues List sheet.
What I have been trying to use is an index match function, but have been unsuccessful in getting the code to work. An example of what I have been using is:
Resolved.Value = Application.WorksheetFunction.index
('Issue List'!$X$2:$X$1000,Application.WorksheetFunction.match
('Priority Table'!I35,'Issue List'!$B$2:$B$1000,0))
Any help would be greatly appreciated.
Thanks in advance!
When you use Worksheet Functions in VBA, you still have to pass in the ranges using VBA language:
So instead of:
'Issue List'!$X$2:$X$1000
you would use:
Worksheets("Issue List").Range("X2:X1000")
And instead of:
'Priority Table'!I35
Just use:
Worksheets("Priority Table").Range("I35")
Note that you can also refer to ranges by names, which can make coding easier and also far safer. When you insert rows in spreadsheets, Excel doesn't automatically update ranges in any VBA code. A reference to I35 will always to be I35.
Instead, define a name for cell I35 in Excel as normal, then refer to it in the code.
For example, if you name I35 as "Issue"
You can refer to the cell by:
Range("Issue")
(If it is a global variable, which it is be default as long as it's a unique name in the workbook, you don't need to use the Sheets("Priority Table") qualifier.
Refer to this documentation for more info on how to refer to ranges in Excel from VBA:
https://msdn.microsoft.com/en-us/library/office/gg192736(v=office.14).aspx

modify (encrypt/decrypt) cell values in rows of datagridview

I've followed this article to use a datagridview to manage data that will be saved into an XML file: http://www.codeproject.com/Articles/32542/Using-XML-as-datagridview-Source
The data will be a list of usernames and passwords.
As such, I need to step through each cell in the columns for 'username' and 'password', and replace the value of the cell with the result of a call to a function that would encrypt or decrypt the value of the cell.
On form_load, after I populate the table with data from the XML file, I want to cycle through these cells and do this to decrypt, and on form close / save, I want to cycle through each cell and encrypt the values before written to file.
I have a function written out to encrypt the data, the part I'm stuck on is how I could step through every cell in the 'username' and 'password' columns of DataGridView1 (as an example) and update the results to the value returned by a function.
I apologize for not having a code example for this question, I do not know how to do this, so I haven't been able to put together a bit of code to try / fail at it.
I imagine it will be something simple like 'For each cell in (whatever statement returns the cells in a given column of the datagridview), ...' , but I'm not sure.
Create a Dataset and use Dataset.ReadXml Method to read the Xml Data
And then choose the specified datatable from the dataset as a datasource for the datagridView. it is easier to manipulate datatable rows.
use the decryption function on the DatagridView.formatingRow event
and before closing Loop over Datatable.rows
For Each row As DataRow In dtDataTable.Rows
row("Pass") = Encrypt(row("Pass")
Next
and encrypt the password before saving it. and Save the dataset into the XML File using the Method WriteXml

Excel data validation missing after re-opening file

I am adding some data validation on the fly using the following:
var cell = sheet.Range["A2", "A1048576"];
cell.Validation.Add(
XlDVType.xlValidateList,
XlDVAlertStyle.xlValidAlertStop,
XlFormatConditionOperator.xlBetween,
"ABC,DEF,123");
This works grand and you will see the ABC,DEF and 123 in the datavalidation dropdown for the column. The issue is after re-opening the sheet later the data validation is gone. An error is shown
Click yes then you are presented with:
Click close and your sheet is displayed with all the data already entered but the data validation is gone entirely.
How do I add the validation so it persists and survives save and re-open?
This happens if the string exceeds 255 chars (in the above example "ABC,DEF,123"). The better solution (if appliable) is to create the list using a reference and not a collection of strings.

Show Cell Range on UserForm; then update

I've been using a crude method to help the user update some cells - by having them in a sheet. Is there any way I can display the various ranges in a userform, one by one, then have the user update them, click a button and move onto the next one?
Essentially, can I have Excel automatically generate an input form based on a range? The process of updating and saving back to the sheet I can do; it's the production of the correct form that I can't.
It's possible to do this, but the only way I can think of is to make a userform that automatically populates itself based on a range passed in. This way you could have different macros in Excel that call the form to populate based on different ranges. I built a proof of concept Excel file for trying this, and it seems to work, the only issue I can think of being that you need to figure out a way to tell the user what input field is what.
I think what needs to be done is to add controls programmatically to a userform (I name the textboxes as the cell address it's going to populate) then when the form is closed loop through all the textboxes and populate the cells with the textbox values.
You can see what I did at:
https://my.syncplicity.com/share/uicgbs3rl0/InputForm.xls
I think all that would need to be done is for you to work out how to add labels for the textboxes, and make sure the form is resized based on the controls you add...
I am not quite shure what you are looking for, but you could insert a second sheet and use it as a "form". An other way could be a dialog box with an input field.
Either way, you present the cells you want the user to change one by one, using a vba-function. You implement a "previous field" and a "next field" button, so the user can step through the range of cells. If the user hits "next field", you save his input and take the next cell from a previous defined range of cells.
You could have a "config field" in which you define the range of cells you want to change.
This is pretty rough and old-fashioned but if you have the data in standard list format - i.e. column headers in the first row of your range and then one record of data in each row below - then selecting a cell within the range and going Data > Form will give you a crude input form with roughly the functionality you need.
You can also do this in VBA by calling the ShowDataForm method of the appropriate worksheet. Just select a cell within whichever range you need first. The macro will remain paused until the user closes the data form