UPDATING QUESTION to include reference I found here***:
Macro button under customized ribbon tab tries to open old Excel file
I wrote a thing here last night that this is related to (Excel telling me it can't access a file I don't want it to access) I've got a Sub that turns a portion of a worksheet into a table and then sorts that table by a column, in preparation for a second procedure that will copy areas of this sheet onto another sheet.
I had been getting an error that said "we can't connect to 'https://...my.sharepoint../BETAV9_8_ItemAccountingTEMPLATEetcetc. Please make sure you're using correct web address."
Now the code is opening a completely different version of this file, that is, BETAV9_9, which I guess it found, unlike before, when it couldn't find BETAV9_8. The thing is, I have no idea what's making it open the other file. Here is what I'm doing:
Sub makeItemChecklistTable()
Dim selectRange As String
Dim lowerBound As Integer
Dim ws As Worksheet
Dim src As Range
Dim tbl As ListObject
Dim sortRange As Range
lowerBound = numberofCERTSRecords() + 1 'This function counts the number of records on another sheet, which is 147
selectRange = "B1:I" & CStr(lowerBound)
Set ws = ActiveWorkbook.Sheets("ItemChecklist")
Set src = ws.Range(selectRange)
ws.ListObjects.Add(SourceType:=xlSrcRange, Source:=src, _
xlListObjectHasHeaders:=xlYes, tablestyleName:="TableStyleLight1").Name = "keywordChecklist"
'Item Checklist table is called keywordChecklist. Before exporting to PTF, sort keywordChecklist by Status in Ascending order
Set tbl = ws.ListObjects("keywordChecklist")
Set sortRange = ws.Range("keywordChecklist[ED_Question_ID]")
With tbl.Sort
.SortFields.Clear
.SortFields.Add Key:=sortRange, Order:=xlAscending
.Apply
End With
End Sub
I mentioned in last night's post that I used MS' guide for finding references to an external Excel file (https://support.microsoft.com/en-us/office/find-links-external-references-in-a-workbook-fcbf4576-3aab-4029-ba25-54313a532ff1?ui=en-us&rs=en-us&ad=us) but at least in all the places I looked, I can't find anything. And if there were a reference to an old file, why would the version before this one try to open BETAv9_8 and now the current workbook is successfully opening BETAv9_9?
When I stepped through this procedure, it inexplicably jumped (2000 times) to another procedure used to modify 2000 strings on a separate worksheet (it takes a string and returns the same string minus a few characters). That worksheet is referred to by the current worksheet via a VLOOKUP function but by the time this procedure has run, all those VLOOKUPs have already been looked up on the current page, i.e. they are displayed already in column H. I'm sorting by column E (ED_Question_ID).
***UPDATE
I do see that I have buttons assigned to macros on my custom toolbar that refer to older versions of this same file. I can fix this using the Export UI function described on this page (Macro button under customized ribbon tab tries to open old Excel file) but 1. I wasn't calling this macro from a button; I was running the procedure directly from the vba code window, and 2. Like I said I've been saving these files in sequence, raising the beta number every time I make a major change. Am I going to have to export and rename all the buttons/toolbar shortcuts every single time I save as a new file name? This seems like an absurd way to set things up by Microsoft.
Related
I know basically the same questions has previosly been asked and answered on many forums, including stack overflow, but none of the answers satisfy my requirements.
I want to press a button, which will copy a range of around 100 cells. I then want to press a different button, in a totally different workbook (which is in no way connected to the first workbook) and that will paste my copied range.
The issue is that I have a filter in my workbook, which will hide some of the cells in the range. These are not being copied but I need to copy the full range. (The reason I want to copy the full range is because the values need to align when I paste it)
My issue with all other given solutions are:
One solution is to remove the filter when I copy the range. This is not something I want to do as I don't know a way to restore the filter. If this is done before I paste the values, the copied range will "exit?" (it will no longer be copied). And due to the files not being connected, I can't perform any actions with the paste button.
Using a loop to copy the range as a array(Variant), This doesn't work since I can't "transfer" that variant to another workbook which is not connected. Or at least I don't know how to do that.
Is there any other method I can use?
It is a bit of a hack, but because both workbooks have access to the set of custom lists defined for Excel, you could create a custom list with the information needed to identify the source range from the target workbook. The code for the copy button would record the range address, sheet name, and workbook name of the selected range as follows:
Sub copy_range_info()
Application.AddCustomList Array("DeleteMe", Selection.Address, Selection.Parent.Name, Selection.Parent.Parent.Name)
End Sub
On the destination worksheet, the code to paste data would look like this:
Sub paste_range_from_other_workbook()
Dim last_list As Variant
last_list = Application.GetCustomListContents(Application.CustomListCount)
If last_list(1) = "DeleteMe" Then
Workbooks(last_list(4)).Worksheets(last_list(3)).Range(last_list(2)).Copy
ActiveCell.PasteSpecial xlPasteValues
Application.DeleteCustomList Application.CustomListCount
Else
MsgBox "You need to copy a range first using that special button"
End If
End Sub
Because this creates a custom list in Excel that will be permanent, I'm deleting it just before the "else" in the code above. It might be advisable to scan the custom list and delete any lists that begin with "DeleteMe" so if someone does a copy without a corresponding paste, it won't result in more than one custom list of this type.
I can perhaps better describe what I want by way of example. I have two Excel workbooks. I want to essentially copy one over to a new workbook as it is (basic copy/paste of everything), and then copy over a specific portion of the other workbook and paste it at the end of the new workbook.
So, there are two input workbooks and one output workbook. And that is how I would like the macro to be structured: There should be a "master" workbook that contains the macro (button) where the two input workbooks are specified by their folder path, and there is an output folder for the new combined workbook (see the very end for example of how I'd like it specified). The first of the input workbooks should have everything in it copied over. Note that this should be dynamic, and should not dictate a specific cell range (as cell ranges could vary). An example of the first input workbook is shown below:
Everything is to be copied over. I don't think that's much of an issue. The tricky part (for me) is to then take a specific portion of the second input workbook and copy/paste that to the end of the first input workbook. I am finding this difficult because the second input folder should be selected by a specific header and then everything under that header should be copied (i.e. select header and then CTRL+SHIFT+DOWN). For example:
This should take "Maturity[5,)" (highlighted in yellow) as the header and then select everything under that, copy it, and then paste it to the matching header at the end of the first input workbook (second row, i.e., Row 8, which, by the way, is the format for all workbooks for this: Rows 1:6 are empty, but should stay like that).
Hopefully you're still with me. After this is done, the new (combined) workbook should look something like this:
Just even getting this far would be extremely helpful. But there is one more issue. By copying over the entirety of the first input workbook, there is an additional header (Row 7; "L-OAS" in the above picture). This header needs to be merged and centered across the range of the new combined workbook, including the second input workbook portion added:
And that's it. Once that header has been merged and centered in the new workbook, the macro should save the new workbook in the output path specified.
Example of input/output paths to be specified:
EDIT: The below is my attempt at doing part (1) -- that is, just copying and pasting the first workbook.
Sub Combine()
Dim wb1 As Workbook
Dim wb2 As Workbook
Dim wsSource As Worksheet, ws As Worksheet
Application.ScreenUpdating = False
shtOutput1.Visible = xlSheetVisible
shtOutput1.Cells.Clear
Set outputRange = shtOutput1.Cells(1, 1)
Set wb1 = Workbooks.Open(Range("USDInputFile1").Value, False, True)
For Each wsSource In wb1.Worksheets
If InStr(wsSource.Cells(1, 1).Value, "Bloomberg") > 0 Then
With wsSource
wsSource.Copy shtOutput1
End With
End If
Next
wb1.Close False
Application.ScreenUpdating = True
With Workbooks.Add
shtOutput1.Copy .Worksheets(1)
Application.DisplayAlerts = False
For Each ws In .Worksheets
Next ws
Application.DisplayAlerts = True
.Close True, ThisWorkbook.Names("OutputFolder").RefersToRange.Value + Application.PathSeparator + "USD Combined Output.xlsx"
End With
shtOutput1.Cells.Clear
shtOutput1.Visible = xlSheetHidden
End Sub
"shtOutput1" is a worksheet in the master workbook (where the macro
button and file paths are located
"USDInputFile1" is a named Cell in the master workbook that leads to
the file path for the first input workbook (i.e. "wb1" -- "wb2" will
be the second input workbook)
Lets just take a step back and look at this from a scalability stance.
You don't want a button to combine things because there is a lot to go wrong and a fair bit of babysitting you will have to do VBA wise and on top of that pressing is a button... ppffft that's work...
No what you want is a seamless update where anything added to Maturity 5 or Maturity 10 will automatically update to your output leaving them to just grow on their own untouched downward like Microsoft intended.
First lets look at the structure, there is some, they have headers but they are not tables and they both have a common ID Date, So change your bottom most headers to ensure they make sense and are Uniform, Unique and Consistant across all iterations of each table. So Mat5_Total or Mat10_Total etc for however many you have.
Insert Tab - Table - Give them proper Shorthand Table names like tblMat10 and tblMat5
Lets open a New File and get them in with Data Tab in the ribbon - External Data - Tranform - Little Down arrow on Close an Load and you only want this in the datamodel not loaded to the Spreadsheet So check Create Connection Only and Add this data to the Datamodel. Uncheck everything else there is no need to clutter your output.
Repeat 3 but for Mat10 only when you get to Close an load instead look to the Right and hit the down arrow on Merge Queries - as a new Query .
Now a new window will pop up Select the two queries and Join them on their Dates as the ID
Now you can close and load to the a sheet.
Give it a spin add some new data to Mat5 or Mat10 and refresh your newly created linking Sheet.
This works for all kinds of data, you can trial this with stocks, shares, CSV, ODBC Connections all sorts of data connections. all you need is a properly formatted infrastructure aka properly formatted tables!
A bonus to this method is if the tables evolve, modifying your Power Query is easy. Just rememeber to go into your connection settings and select refresh on open and if you like set it to refresh every 5 minutes.
7 Optional Bonus - Once this output table has been made it will be compatible with any external programs, because it is a correctly formatted output table.
I am looking at inserting/pasting a range of text data (40 columns) from Excel into bookmarks in Word. Most of the answers are done using Excel VBA, which is so not practical for my use case as I will have the Word document open, add a button that would run this 'import data' macro. I actually already have a button in the doc that inserts images into bookmarks, so that's one more reason I don't want to do it via Excel VBA.
I know this is not great code, but for the lack of definite leads, I'm throwing it here and hope that this gives you an idea of what I'm trying to achieve:
Sub ImportData()
Workbooks.Open ("\Book2.xlsm")
ActiveWindow.WindowState = xlMinimized
ThisWorkbook.Activate
Windows("Book2.xlsm").Activate
Range("A1:AF1").Select
Selection.Copy
Documents("test.docm").Activate
Selection.GoTo What:=wdGoToBookmark, Name:="Overlay_1"
Selection.Paste
End Sub
PS: It would be great if I could sort of 'transpose' the 40 columns into rows as it is pasted in Word.
Here's an update to my code based off #Variatus 's advice:
Sub ImportData()
Dim wb As Workbooks
Dim ws As Worksheets
Dim objSheet As Object
Dim objWord As Object
Set objWord = CreateObject("Word.Application")
wb.Open ("C:\Users\pc\Documents\Book2.xlsm")
Set objSheet = CreateObject("Excel.Application")
ActiveWindow.WindowState = xlMinimized
Set ws = Workbooks("Book2.xlsm").Sheets("Sheet1")
ws.Range("A1").Value.Copy
With objWord.ActiveDocument
.Bookmarks("Bookmark_1").Range.Text = ws.Range("A1").Value
End With
End Sub
I'm getting this error:
Runtime Error '91':
Object variable or With block variable not set.
Notice how I stuck with a single cell reference for now (A1). I'll just update my code as I learn along the way :)
When you click the button in your Word document you want the following sequence to be initiated.
Create an Excel application object. Make sure that a reference to Excel has been set (VBE > Tools > References) so that Excel's VBA objects are available.
Using the Excel application object, open the workbook. Create an object. Place the object in an invisible window.
Definitely forget about activating or selecting anything in either the workbook or your Word document. The latter is active and remains active from beginning to end. The bookmarks are points in your document you can reference and manipulate by name without selecting them. The Excel workbook is invisible. You can access any part of it using the Range object.
The data you want from your workbook are contained in Worksheets. Be sure to create an object for the worksheet you are about to draw data from.
Excel tables don't translate very well into Word tables. If you do want to go that way I suggest that you use VBA to create the table you want in Excel (transpose the data before you import them into Word). However, you may find it easier to first create the tables you want in Word and then just copy values from your Excel source into the word tables. That would involve taking one cell value at a time and placing it into one Word table cell. Transposing would be done by the algorithm you employ.
Close the workbook. Quit the Excel application. Set the Excel application = Nothing. At the end of your macro everything is as it was before except that your document has data in it which it didn't have before.
Each of the above six points will lead you to at least one question which you can ask here after you have googled the subject and written some code. In fact, I strongly urge you to create one Main procedure (the one which responds to your button click) and let that procedure call various subs which carry out the individual tasks and functions to support the subs. The smaller the parts you create the easier it is to write the code, to find questions to ask and get answers to them. If you plan your project well expect to have about 12 procedures in it by the time you are done. Good luck!
Is it possible to have a new Excel sheet created and then VB code automatically put in that sheet?
Here is what I have done so far. A sheet called Template has the input for all of the information that users need to input. I have various checks to make sure that all fields are filled out and are filled out correctly before anything else will execute. When they click on a certain cell to execute the script it will open a Word document and import all required information in it. Then a new sheet in Excel is created. A name is given to the new sheet, based on what was selected in the ComboBox (cboSites) from the Template sheet. I also have a check in place to make sure there already isn't a sheet with the same name. I have all of this working without any issues.
From here what I would like to do and can't think of how to do it, is when the new sheet is created I want VBA code automatically dumped in this new sheet. I know the code that I want to use, but I just have no idea how to get it so it will automatically put that code with that sheet.
Is this possible to do or can only a new sheet be created and formatted, without being able to import any code into it?
Here is a sample code which will insert
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
MsgBox "Hello World"
End Sub
in a new sheet in a new workbook.
Sub Sample()
Dim wb As Workbook, ws As Worksheet
Dim VBP As Object, VBC As Object, CM As Object
Dim strProcName As String
Set wb = Workbooks.Add
Set ws = wb.Sheets(1)
Set VBP = wb.VBProject
Set VBC = VBP.VBComponents(ws.Name)
Set CM = VBC.CodeModule
strProcName = "Worksheet_SelectionChange"
With wb.VBProject.VBComponents( _
wb.Worksheets(ws.Name).CodeName).CodeModule
.InsertLines Line:=.CreateEventProc("SelectionChange", "Worksheet") + 1, _
String:=vbCrLf & _
" Msgbox ""Hello World"""
End With
End Sub
Please amend it to suit your needs.
You need to ensure that Trust access to Visual Basic Project is selected. To select it, follow the steps mentioned in THIS LINK
I am not aware of an easy way to put code in an Excel file.
Someone might think about changing the XML structure directly (xlsx files are basically a zipped directory of xml and code files).
But did you consider using XLAM (Excel addin) files, that can contain code and be imported for all users, who ever need to use it. And would open up with Excel, when the users start it. Depending on your setup, this could help you?
Look into the VBProject property of the workbook you are generating. You should be able to manipulate it, adding new VBComponents items containing the code you want.
http://msdn.microsoft.com/en-us/library/office/ff194737.aspx
This will require the appropriate security settings to do.
Here's a thread on another site related to this topic:
http://www.mrexcel.com/forum/excel-questions/663848-access-vbulletin-project-not-trusted.html
I haven't tried it myself, so I can't give much more detail.
I've got an Access 2007 database on which I have created around 15 SQL queries to process specific data, I have created a main frame navigation menu using menus in Access, I now need to extract all th queries to Excel using VBA code, I have managed to do this with the code below by creating a button and specifying this code to it.
Private Sub query1_Click()
DoCmd.TransferSpreadsheet acExport, _
acSpreadsheetTypeExcel9, "Total Users and Sessions", _
"C:\UsersandSessions.xls", , "Total Users & Sessions"
End Sub
Now my problem at the moment is that fine the query is exported to Excel, but it is done so without any formatting applied at all, I would like to add some formatting at least to the headers and maybe a title inside the spreadsheet, and one thing I dont really like is that all records are being started from the first cell. Also I would prefer that if I hit that button again in Access and the Excel spreadsheet has already exists with that query output then when clicked again it will write again to a the next available sheet.
Any suggestions or ideas a very welcome.
The short story, is you can't. You might be able to do some scripting on the Excel side to format the resulting file. If you want something pretty, you probably want to create a report.
You could, instead mount the excel sheet as a table, and then on a separated sheet in the excel file, reference the first sheet, and format the second sheet for viewing.
if you use DoCmd.TransferSpreadsheet and create an original and then edit it so that the formatting is correct, you can then run DoCmd.TransferSpreadsheet again and it will update the file with the values but keep the formatting.
However, if a human then changes the file by adding new tabs, or adding calculations, etc, then the DoCmd.TransferSpreadsheet will no longer work and will fail with an ugly error message. So what we do in our enviroment is DoCmd.TransferSpreadsheet to an original file with formatting, and follow that up in the VBA by copying the file to the users desktop, and then opening that copy so the user doesn't mess up the original source excel file.
This approach is a minimum code, clean, and easy to maintain solution. But it does require a extra "source" or original file to be hanging around. Works in Access 2007.
You also would like the results to end up on a new tab. Unfortunately, I think it will take some excel automation to do that. The VBA inside Acccess can call a function inside the VBA in Excel. That VBA could then copy the tabs as needed.
My idea would be a hybrid of Excel automation from Access and creating a template in Excel as well that would have a data table linked to your query.
To start create your data table in Excel. You can start three rows down and two columns to the right if you want or wherever. Go to your data tab and click access, find your db, choose your query you want to link to, choose table as the radio button but click properties next instead of ok, uncheck the enable background refresh, this part is critical ... under the definition tab in the connection string you will see a part that says Mode=Share Deny Write change that to Mode=Read, this will make sure that the query refreshes without errors from an MS Access VBA while the db is open and will keep your users from writing back to the db in case your query is a writeable query. Once you set that up you can adjust the table formatting however you choose from the table design tab and it will keep that formatting.
For the purposes of this we are going to assume you started the table in cell B4 ,and your named the worksheet CurrentDay, for purpose of the following VBA example be sure to replace that reference with your actual placement.
Next go back to Access and write your VBA first ensure that in your VBA window you have the reference to Microsoft Excel 12.0 Object Library is selected by going to Tools > References and selecting it from the alphabetical listing.
Create your sub as follows:
Sub query1_click()
Dim xl as Excel.Application
Dim wbk as Excel.Workbook
Dim wks as Excel.Worksheet
Dim RC as Integer
Dim CC as Integer
Set xl = New Excel.Application
Set wbk = xl.wbk.Open "X:\Filelocation\FileName.xlsx" 'name and path you saved the file you previously created
xl.Visible = True
'The above is not necessary but you may want to see your process work the first few times and it will be easier than going to task manager to end Excel if something fails.
RC = xl.Application.CountA(xl.wbk.Worksheets("CurrentDay").Range("B:B")) + 3 'This will count the rows of data in your table including your header so you can copy the data to another tab dynamically as the size of your table expands and shrinks we add 3 to it because we started at row 4 and we need the location of the last row of the record set.
CC = xl.Application.CountA(xl.wbk.Worksheets("CurrentDay").Range("4:4")) + 1 'This counts the header row and adds one space because we will use this as a location holder for our copy / paste function
Set wks = xl.wbk.Worksheets.Add
wks.Name = format(date(),"MM_dd_yy") 'this will name the tab with today's date... you can eliminate this step if you just want the sheets to be the generic Sheet1, Sheet2, etc.
With xl.wbk
.Worksheets("CurrentDay").Range(Cells(4,2),Cells(RC,CC)).Copy
.wks.PasteSpecial xlPasteValues 'This pastes the values so that the table links do not paste otherwise every tab would just refresh everyday.
.wks.PasteSpecial xlPasteFormats 'This gets your formatting.
.RefreshAll 'This will refresh your table
Wend
With xl
.Save
.Close False
.Quit
Wend
Set xl = Nothing
Set wbk = Nothing
Set wks = Nothing
End Sub
That should get you to have your data to not start on A1 of your sheets, save your old data each time, and automate the steps from access.