I am looking to write a macro which copies formatting from one graph and applies it to multiple other graphs.
What I am struggling to do is determine a way to allow the user to set the template chart and then select the multiple other charts. While this could be done with a combo box if the user knew the chart name, I am trying to do it without them knowing the chart name.
As such I was thinking of having a user dialog box where the user can select the base chart, and then select the charts to apply the formatting to. Just like refedit for a range. However I cannot figure out how to reference to a graph from within a user form.
Can this be done, and if so, how?
Here is what will get you started.
Place Two ComboBoxes and two Image Controls on the userform.
Let's say your worksheet looks like this
In the UserForm_Initialize() event populate the Chart names in both the comboboxes. For example
Dim ws As Worksheet
'~~> Prepare your form
Private Sub UserForm_Initialize()
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim ChartObj As ChartObject
For Each ChartObj In ActiveSheet.ChartObjects
ComboBox1.AddItem ChartObj.Name
ComboBox2.AddItem ChartObj.Name
Next ChartObj
End Sub
So when you run the form, it will look like this
In the click event of the comboboxes, use the Stephen Bullen's PastePicture code from HERE to show the chart in the userform. For example
Private Sub ComboBox1_Click()
ws.Shapes(ComboBox1.Value).CopyPicture
Set Me.Image1.Picture = PastePicture(xlPicture)
End Sub
Private Sub ComboBox2_Click()
ws.Shapes(ComboBox2.Value).CopyPicture
Set Me.Image2.Picture = PastePicture(xlPicture)
End Sub
This is how the form will look.
From there on, Now you have the names of the charts. Simply use them to work as you please.
Hope this helps.
The following code should allow you to do stuff with the selected chart area(s), where you can either select one or many charts:
Public Sub ProcessSelectedCharts()
Dim i As Integer
Dim chart_obj As ChartObject
Dim chart_area As chartArea
If TypeOf Selection Is DrawingObjects Then
For i = 1 To Selection.Count
If TypeOf Selection(i) Is ChartObject Then
Set chart_obj = Selection(i)
Set chart_area = chart_obj.Chart.chartArea
Call ProcessChart(chart_area)
End If
Next i
ElseIf TypeOf Selection Is chartArea Then
Set chart_area = Selection
Call ProcessChart(chart_area)
End If
End Sub
Public Sub ProcessChart(obj As chartArea)
' Do something...
End Sub
You may want to refine this a little, i.e. this should work if the user selects the actual charts, but may fail if he only selects a particular element within the chart.
Ok, the next question is, when do you invoke this from your user form. So first of all, your user form should be modal of course, to allow the user the select anything. So how do you notice when the users actually selects anything?
I can think of three methods, and I'll list them from best to worst (the last 2 only described very briefly as I wouldn't recommend using them):
Use the "Worksheet_SelectionChange" event on your worksheet, and have it call a method within your userform to inform it that the selection has changed. Now you'll just need to check if, and which charts have been selected (see code above), and run your algorithm.
Run a timer in your userform and regularly check the active selection.
Hook mouse events by DLL calls and register any mouse clicks, then check for selection changes.
That should allow you to create a ref-edit like feature for selecting charts on your worksheet from a userform.
Related
I am looking for a way to distinguish between the charts created by my code and the charts created "manually" by the user.
Using chart.name would work if I would set a specific name_prefix or something for the charts but this property is of no use to me as the names can be changed dynamically by the user. I have thought about looking at chart like at shape and change its ID, but no luck with it either.
I have checked chart/shape object model and I cannot find a property, which I could use to somehow distinguish "my charts" from all charts on a sheet collection.
The general idea is that I create a chart with VBA and when user activates it, chart.activate event opens a userform. This userform should open when user activates chart created by my code and not on activating ANY chart on the sheet. I know how to do everything except how to distinguish the charts.
Any ideas how this could be done?
Thanks in advance!
EDIT: I have also thought about adding some information to series names, again, prefix type of info. That would work, but once again - it could be easily changed by the end user and this is what I would like to avoid.
It should be good if you posted the code you use. I (only) can suppose that you activated charts events.
Please, try the next way, which should work with events activated, or not:
Copy the next code in a standard module. It is a Sub which will be assigned to all created charts. It can be used instead of (existing) events, or with events working:
Sub CreatedChart()
Dim ch As Chart
Set ch = ActiveSheet.ChartObjects(Application.Caller).Chart
'you can call the form in discussion here...
Select Case ch.Parent.Name
Case "CrChart1", "CrChart2"
MsgBox "Here you can do something in case of Chart 1 or Chart 2..."
Case "CrChart3"
MsgBox "Here you can do something in case of Chart 3..."
End Select
End Sub
Copy the next code in a module, too. It will create charts and assign the above Sub to them:
Sub testChartsCreate()
Dim ws As Worksheet, ch As ChartObject, i As Long
Set ws = ActiveSheet
For i = 1 To 3
Set ch = ws.ChartObjects.Add(left:=1, _
top:=10, width:=100, height:=100)
ch.Name = "CrChart" & i
ws.Shapes(ch.Name).OnAction = "CreatedChart"
ch.Chart.ChartType = xlLine
'do here all your charts configuration...
Next i
End Sub
You can identify which of all existing charts on a sheet have been created by the above code. Please, take care to also have some manually created charts, or programmatically, but not by the above code (type), which assigns that specific Sub:
Sub testIdentifCrCharts()
Dim sh As Worksheet, ch As ChartObject, i As Long
Set sh = ActiveSheet ' use here the necessary sheet
For Each ch In sh.ChartObjects
Debug.Print ch.Name, isCreatedChart(ch.Chart, sh)
Next
End Sub
Private Function isCreatedChart(ch As Chart, sh As Worksheet) As Boolean
If sh.Shapes(ch.Parent.Name).OnAction = "CreatedChart" Then
isCreatedChart = True
End If
End Function
I used ch As Chart like the first function parameter, for the case of Charts to be checked, not ChartObjects...
The above solution may look complicated, but it is very easy to be understood and applied, in fact.
Please, test the above suggestion and send some feedback.
One potential idea would be to put your magic value in MailEnvelope.Introduction. This is a VBA-settable string property you likely won't ever use for its intended purpose, and it isn't exposed in the UI for a user-created chart.
I have a sheet with a bunch of ComboBoxes(form control) and I want to detect when a user changes any one of them and write text in a cell. Using Worksheet_Change on the target cells doesn't work. I have tried a bunch of things that don't work. I'm not sure what needs to be in the private sub line or the if statement.
Private Sub DropDowns_DropButtonClick()
If ActiveSheet.DropDowns.Value > 1 Then
Cells(13, 5).Font.Bold = True
Cells(13, 5).Font.Color = vbRed
Cells(13, 5).Value = "!!! Selections have been changed. !!!"
End If
End Sub
I have tried
ComboBox_AfterUpdate()
ComboBox_Change()
DropDowns_AfterUpdate()
DropsDowns_Change()
and anything else I could find. I've also tried a few different things in the if statement with no luck.
I appreciate any help.
Chris
If I'm reading you correctly, you're comboboxes are in a userform. If I'm correct, simply open your userform in 'Visual Basic' and double click on the relavant combobox. This will open the code pane and create an empty Private Sub routine called 'Private Sub <Combobox Name> ()'.
Enter your code to place your data in the sheet (or whatever else you want) into the subroutine and Bob should be your uncle.
Apologies in advance if there's something I've missed.
RannochRob
Edit...
OK, my mistake, it's a form control.
My first comment is that it's easier to use an activex control if you can... however, with a form control, should (a) Use the cell link box in the 'Format Control' drop down ('Control' tab) to place the result in a cell... however, that result will not be the content of the box but an integer equal to the position of the selected entry on the list of entries in the combobox. You then need to (b) assign a macro to the combobox which will pick up the result and use it to get the required information from the range containing the list of entries. Like I say, much easier with an activex control...
RannochRob
Here's how you can do it by assigning a macro to the combobox (right click on the combobox>assign macro) as #BigBen mentioned in the comments section:
Option Explicit
Sub DropDown1_Change()
Dim sht As Worksheet
Dim dd As DropDown
Set sht = ThisWorkbook.Worksheets("Name of your Worksheet") 'Name of the worksheet in which the combobox is located
Set dd = sht.DropDowns("Drop Down 1") 'name of your combobox
sht.Range("G1").Value = "The selected value is: " & dd.List(dd.Value) 'dd.value returns the index of the selected value
End Sub
You can use the same code for each one of your comboboxes.
For demonstration purposes i have used the following set-up:
You can easily modify the code to best fit your needs.
I am currently working on an Excel tool that I have equipped with one button and one shape-object.
The button is a select button to "select" the shape object. The idea is to Select a shape-object a Picture and change its color after selecting it.
I was able to locate the problem to the clicked Sub of the Select button.
To check if I'm correct I have written a the Macro Select_MyClicked and afterword used the call instruction to invoke the macro from within the Clicked-function of the select button.
Sub Select_MyClicked()
Dim ElementName As String
Dim Shp As Object
Set Shp = Sheets("Tabelle1").Shapes(ElementName)
Shp.Select
End Sub
==================================================================
Private Sub CommandButton3_Click()
Call Select_MyClicked
End Sub
==================================================================
What is interesting now is:
When I use the Button the Image is selected but in the Picture format register there i nothing selectable
If I cklick on the Image itselfe or use the Select_MyClicked Macro indepentently everything in the picture format register is selectable
I also tried to write the select instruction directly into the Button-Clicked private sub. Same result nothing selectable
What I want to do is select an image and change its color. My second question is does somebody know how to open the Colorpennel (with the many colored Rectangles) using vba ?
You need to reference the Shape by its Name. I assigned the name "myshape" to the Shape before running:
Sub Select_MyClicked()
Dim ElementName As String
Dim Shp As Shape
ElementName = "myshape"
Set Shp = Sheets("Tabelle1").Shapes(ElementName)
Shp.Select
End Sub
The code runs even if Tabelle1 is not the active sheet.
I have finally find the solution. It seems like it makes a difference which button you use. In my case it had to be the control elements not the activeX elements
I am new to VBA. i have few shapes in a worksheet.
I want to get the name of shape to appear in combobox and character name in another Combobox, when any particular shape is selected. so i can rename that shape and link to particular excel column.
i have tried following.
With Selection
ActiveSheet.ComboBox1.Value = ActiveSheet.Shapes(Application.Caller).Name
End with
Not sure where to assign above code.
I tried assigning above code to a shape with .onaction as macro, it work but a marco assiged shape cannot be edited further(For design purpose).
Also It would be great if i can delete selected shape.
Thank you in advance.
You can use your code for any shape and you can change the code whenever you want, but assigning a macro, she shape will will not be selected when clicked... It becomes a kind of control.
Excepting the case when you force it to select:
Debug.Print ActiveSheet.Shapes(Application.Caller).Name
shW.ComboBox1.value.Shapes(Application.Caller).Select
You can change the code from right click context (on the chart bottom side) and choose 'Assign Macro... -> Edit'.
You can find the selected shape using the next code:
Sub testSelectedShape()
Dim shW As Worksheet, sh As Object, selSh As Object
Set shW = ActiveSheet
If TypeName(Selection) <> "Range" Then
Set selSh = Selection
Set sh = shW.Shapes(selSh.Name)
Debug.Print selSh.Name
shW.ComboBox1.value = selSh.Name
End If
End Sub
You can delete it simple using sh.Delete...
I have a worksheet that runs a weightlifting meet. Last year I had created a tab that would give information on the current lifter and on who was lifting next.
left side - Display, right side - input tab
When I input an "x" in columns R, S, T, or W on the data tab, it changes the information in the BenchGenerator tab, like so:
Updated Display tab
What I want to do is make a userform display to run on a different screen so people can see this information. I had accomplished this last year by widening excel and using two view windows - display on the second screen and running the meet on the computer. It was ok but very clunky looking. With a floating userform tab, it would look fantastic. I am new to this, but got the form floating:
Private Sub Worksheet_Change(ByVal Target As Range)
UserForm1.Show (vbModeless)
End Sub
And got the labels to initially populate:
Userform Display
Using this code:
Private Sub UserForm_Activate()
UserForm1.Label1.Caption = Sheets("BenchGenerator").Range("c4").Value
UserForm1.Label2.Caption = Sheets("BenchGenerator").Range("c5").Value
UserForm1.Label3.Caption = Sheets("BenchGenerator").Range("c6").Value
UserForm1.Label4.Caption = Sheets("BenchGenerator").Range("d3").Value
UserForm1.Label5.Caption = Sheets("BenchGenerator").Range("d4").Value
UserForm1.Label6.Caption = Sheets("BenchGenerator").Range("d5").Value
UserForm1.Label7.Caption = Sheets("BenchGenerator").Range("d6").Value
End Sub
What it doesn't currently do is update the captions when I input the "x" in the data tab.
As I mentioned, this is my first foray into userforms and looking through mountains of code trying to figure this out, it will not be my last as there is lots to accomplish with them.
Thanks in advance for any help!
You're pretty close to getting this to work. The problem is that your calling a new form every time a change occurs.
Declare your form as an object outside of the Sub that creates (Show) it.
You can then access it to update labels from another Sub that has the same scope.
Create an UpdateForm sub for example and call it from your Worksheet_Change event.
Try this, place the following code in a new Module:
Dim myForm As Object
Sub launchForm()
Set myForm = UserForm1
myForm.Show (vbModeless)
End Sub
Sub updateForm()
Dim wks As Worksheet
Set wks = Sheets("BenchGenerator")
'Update label values here
myForm.Label1.Caption = wks.Range("C4").Value
myForm.Label2.Caption = wks.Range("C5").Value
myForm.Label3.Caption = wks.Range("C6").Value
myForm.Label4.Caption = wks.Range("D3").Value
myForm.Label5.Caption = wks.Range("D4").Value
myForm.Label6.Caption = wks.Range("D5").Value
myForm.Label7.Caption = wks.Range("D6").Value
End Sub
If you use Worksheet_Change to update the form you'll want to verify the form exist or just skip any errors in the event if it doesn't.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
updateForm
End Sub
Not sure if there is an easier way to do it, but I made a concatenation routine to batch out my label setup and updates to quickly create/copy/paste all the code.
Just in case anyone didn't know how to do this