Manipulating objects in design view - vba

I have worked on several projects now where I have been stumped by MS Excel and MS Access where I cannot use VBA to manipulate objects whilst in design view. They are very simple tasks such as changing the name of the labels on a userform in MS Excel or adding new textboxes to a report in MS Access but they seem to be impossible as any macro will only be used upon activation of said userform or report and so everything is just done in runtime.
To focus on one, In MS Excel I want to be able to run a code which will go through all the labels on my userform and rename them from "Label1", "Label2", etc... to "Lbl1", "Lbl2", etc... for instance but I cannot just click a button to run a macro on the design of the userform which would run through all the labels and change their names. If I am able to do this then I can be much more efficent with the rest of my runtime code. Without it, I have the option of renaming every single label I have but there are near 100 labels and I want to do this through VBA as I already can see that it would be very useful to know how to run code in design view of these Visual Basic elements.
Please could you advise whether it is possible to manipulate these VB objects in design view?

You can program the project from code if you set a special macro permission.
Details are on Chip's site: http://www.cpearson.com/excel/vbe.aspx

No, it's not possible. If you have a designer open for Form1 and type Form1.Show in the immediate pane, the VBE will close the designer before it brings up the form. That's just the way it is.
Now, if you have labels Label1, Label2 and Label3, you have what I like to call meaningless identifiers. Renaming them to Lbl1, Lbl2 and Lbl3 will make things even worse.
And if you're referencing them anywhere in code, renaming them will break your code. It's even worse with buttons or anything else with events you're handling: renaming Button1 to Btn1 will not rename the Button1_Click() procedure to Btn1_Click().
Use meaningful names. If Label1 is sitting atop a textbox for, I don't know, some username, then name it lblUserName or UserNameLabel. Use meaningful names. Always.
I've written a refactoring tool for renaming things, that deals with event handlers and many other things; you could right-click a reference to Label1 in your code, select Refactor > Rename from the context menu, enter a new name, and the tool renames all references, and the control itself. The tool in question is called Rubberduck, and does quite a lot more than just letting you rename things, too.
If the labels aren't referenced anywhere in code, then they don't need a name. Why bother?

You can run code from a normal module to alter the design of a userform. You must have trusted access to the VBA Project in your Trust Center settings. Then it's simply a question of using the Designer property of the relevant VBComponent:
Sub foo()
Dim ctl As MSForms.Control
Dim lCounter As Long
lCounter = 1
For Each ctl In ThisWorkbook.VBProject.VBComponents("Userform1").Designer.Controls
If TypeName(ctl) = "Label" Then
ctl.Name = "lbl" & lCounter
lCounter = lCounter + 1
End If
Next ctl
End Sub
The form must not be loaded when you run this.

Related

Copying the content of multiple UserForm textboxes to clipboard

I built a Microsoft Word template with a userform containing textboxes. I want to copy the data of two textboxes into the clipboard separately upon submitting the completed userform. Just to clarify I want each textbox to have its own entry into the clipboard for easy access in the future.
Below is the code I'm using but when I repeat the procedure it replaces the first textbox in the clipboard with the second. Any help would be greatly appreciated.
Sub ComandButton_click()
Dim clipboard As MSForms.DataObject
Set clipboard = New MSForms.DataObject
clipboard.SetText Me.TextBox1.value
clipboard.PutInClipboard
End Sub
EDIT (additional background):
For accessing the information put on the Clipboard I created a custom QAT. One of the buttons on the toolbar opens the clipboard so they can easily begin to paste the name they need at any one time. Most reports involve two people so I want to send the value of two textboxes into the clipboard as if you individually selected and copied each name. My first idea was to assign a keyboard shortcut to the value of the two textboxes but I settled on utilizing the clipboard tab.
Given what you've told us, I'm guessing you're calling up the Office Clipboard. This is different from the Windows Clipboard, which is what your code is using. The Office Clipboard is not exposed to the developer (for internal, MS use only). There is a way to put information on it, but I'm uncertain how reliable it is; YMMV (your mileage may vary).
The code for your UserForm to call a procedure responsible for writing the information:
PutContentOnOfficeClipboard Me.[textBoxName].Value
PutContentOnOfficeClipboard Me.[textBoxName].Value
The procedure writes the text to the end of the document, copies it, then deletes again. In my tests, this all shows up on the Office Clipboard:
Sub PutContentOnOfficeClipboard(s As String)
Dim rng As word.Range
Set rng = ActiveDocument.Content
rng.Collapse wdCollapseEnd
rng.Text = s
rng.Copy
rng.Delete
End Sub
If it turns out to be unreliable, then you need a different approach. Here are some thoughts on alternative methods...
A taskpane is optimal as it makes the information visibly available users. Unfortunately, task panes aren't available to the VBA Developer. They can be used from a VSTO solution or an Office-JS solution, but that may be more effort than you're willing/able to put into the project (steep learning curve, enterprise deployment requirement, etc.)
Besides keyboard shortcuts (which aren't a bad idea to have in addition to any visible interface):
A dropdown list on the QAT or the Ribbon
Two buttons on the QAT or the Ribbon
Modify the Right-click (context) menu with two controls to which you can write the names as needed. (Requires call-back macros to make the dynamic update)
Save the entries as AutoText/Building Blocks, possibly to use in conjunction
with a BuildingBlock content control (which can be filtered to show only your entries; AutoText can also be used selectively from the keyboard).
Make a small, non-modal UserForm with buttons. You could optionally use the Windows API to make it "always on-top".

Word VBA: Make macro easy to run

I've made a form-letter document with a macro that performs the mail merge. I don't want the user to have run it from the menus, and I want this to be portable. If there's a way for a button to appear on each user's ribbon or quick command menu, I'm not familiar with it.
So I put a button in the document itself. Unfortunately, every form-letter created has the same button in it. I suppose I could write the code to delete every one, but I think that would be slow.
Is there a way to assign a shortcut key to an existing macro, and have it reside in the document?
I had to implement something pretty similar to what you were referring to some 10 staff. My solution (by no means as portable as desired) was to export the macros and forms from my Normal template to the other users, I coupled this with Ribbon customization and it worked well. Unfortunately, when a change was needed, I had to trudge over to everyone's machine individually.
I would suggest you stick with your solution of deleting button after the merge is complete. Here's some code to help with that:
Sub DeleteCommandButton()
For Each o In ActiveDocument.InlineShapes
If o.OLEFormat.Object.Name = "CommandButton1" Then
o.Delete
End If
Next
End Sub
Good luck, hopefully this helps.

View names of controls in worksheet

So I feel a little foolish asking this question. I have spent plenty of time searching and only found a crude work-around. I have given this due diligence before posting.
For controls placed within a worksheet I cannot pull up the properties or even view the name to reference in code. The work-around I came across is if you right-click on the control (listbox in this case) and choose assign macro. It will suggest a macro name with the control name (e.g. ListBox13_change). In the code I refer to this listbox as Sheet2.ListBox13, but getting an error message for missing object.
With ActiveX controls or controls within a userform I can view the properties. I don't know why I am having trouble with this case.
Any guidance is much appreciated.
You can get the real name of the form control from the Immediate Window in the VBE by executing this line:
?Sheet2.Shapes(1).Name
Form controls are actually shapes in the object model.
The above assumes you have no other shapes on the worksheet.
Of course you can also see the name (and edit it) from the Name Box if the control is selected.
Once you have the name you can use it in code like so:
MsgBox Sheet2.Shapes("List Box 1").Top

Excel: Fixed Button Position

Needing some help attaching an Excel/VBA button on an Excel sheet. I need it to stay in the same position on the screen regardless of how I scroll or zoom. Preferably, I need this on the bottom left or right of the screen.
I have tried adding a button. Then, I right clicked on the button. Clicked on Format Controls -> Properties -> selected Don't Move or Size With Cells. Am I missing something that's making this not work?
Thanks!
I know this post is old, but here's to anyone it could be useful. The VisibleRange property of ActiveWindow can solve this problem. Use something like this:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
With ActiveSheet.OLEObjects("MY_BUTTON'S_NAME")
.Top = ActiveWindow.VisibleRange.Top + ActiveWindow.VisibleRange.Height - 5
.Left = ActiveWindow.VisibleRange.Left + ActiveWindow.VisibleRange.Width - .Width - 5
End With
End Sub
Here is the idea that I put across the comment earlier today :) Typically we can get a Floating User Form by setting the Modal property of the form to be 0 which is indeed a Modeless state.
Basic Points to consider:
Look & Feel of the form to make it look like a Button (Not show title bar/Not Resizable/
Hidden Close Button etc)
Setting the position of the Button
Which Event should trigger the form-button (WorkBook Open)
What would you do with Form Initialize Event
Whcih Events should keep it stick to the same position alive
Further Points to consider:
You might only want to keep this button vissible for the workbook you are working, and if you open another instance of a workbook, do you still want to keep the button
If you minimize the Excel Window instance, how do you plan to manage the state of the button and keep it visible
Post about keep displaying a form even the workbook is minimized.
One other great reference I happend to see, (little bit technical) but worth the shot - at least to get to know the certain properties/methods that you could make use: Extending VBA User Form Control.
The article include the following info, and please note the last line as well :)
They give you access to capabilities that are not available from VBA or from the objects (UserForms, Workbooks, etc.,) that make up a VBA Project. When you call an API, you are bypassing VBA and calling directly upon Windows. This means that you do not get the safety mechanisms such as type checking that VBA normally provides. If you pass an invalid value to an API or (a very common mistake) use a ByRef parameter instead of a ByVal parameter, you will most likely completely and immediately crash Excel and you will lose all your unsaved work. I recommend that until you are confident that your API calls are solid you save your work before calling an API function.
Add new Row on the beginning of your WorkSheet and set your button on it, then:
Freeze Top Row
Right click → properties → placement → change to 3.

VBA Status Bar

I am working on a Word VBA macro app for 80 or so users. The office has high staff turnover, so training suffers, and so one of the self imposed requirements for this project is comprehensive, friendly documentation. However, to supplement this, and to save newbies having to open up a 100 page document when they want to try something new, I want a status bar on every userform (there are five) that provides contextual help. I find tooltips annoying.
I don't have a lot of experience, so I was wanting to
Essentially, I have a file containing every status string. (This is currently a text file, but I was wondering if I should use a spreadsheet or csv for ease of editing by other staff in future.) Every control has a MouseMove event which refers to a function: getStatus(cID) that opens the file, grabs the line and displays it in the status label. It also grabs a few parameters from the same line in the file, such as whether the label is clickable (to link to a page in the help file), and what colour the label should be.
So a few questions really:
Will the application be slow if a userform is constantly referring to a file? It feels fine to me, but I've been in it far too long, and I'm the only user accessing that file. There will be 80 constantly accessing it.
Is MouseMove over a control the best way? Should I instead use co-ordinates?
Most importantly (in terms of me having to do as little work as possible) is there some way to do this so that I do not have to have a MouseMove event on every single control? I have a good few hundred or so controls, each with their own identifier (well, not yet, but they will if this is the only way to do it). Maybe when the form loads I could load ALL the possible status lines so they're ready for whenever the control is moused over. But then, maybe the loading time is negligible?
Appreciate any ideas or thoughts - especially if VBA already has a whole range of functions to do this already and I'm just trying to reinvent the wheel. I can't use the application status bar, because the user rarely sees the application itself.
Thanks!
EDIT:
It is for both data entry, clicking around and a bit of document generation.
It is a controlled environment so macro security issues aren't a big concern for me - and if something goes wrong it's someone else's fault or problem :)
Is this data entry app or do they just click stuff? Because often the field with focus is different to the item the mouse is hovering over, this can cause a lot of confusion.
Constantly reading from a file is a huge waste of time and resources - it is much better to load them only once into an array or collection when the form is loaded.
On MouseMouse event is better than coordinates because you can move things around without worrying. It's a lot of code but you should be able to generate most of that if you have a list of control names because the code should be identical.
ie
Sub Control_MouseMove()
DisplayStatus(Control)
End sub
I would consider the StatusText property and ControlTipText property of controls for this kind of help.
StatusText
This example sets the status bar help text for the form field named "Age."
With ActiveDocument.FormFields("Age")
.OwnStatus = True
.StatusText = "Type your current age."
End With
ControlTipText
This can be assigned from the property sheet for the control.
Private Sub UserForm_Initialize()
MultiPage1.Page1.ControlTipText = "Here in page 1"
MultiPage1.Page2.ControlTipText = "Now in page 2"
CommandButton1.ControlTipText = "And now here's"
CommandButton2.ControlTipText = "a tip from"
CommandButton3.ControlTipText = "your controls!"
End Sub