I want to loop select all slicer items within a certain range . Let's say , all items from 3 to 6 . My slicer contains the following items 1 , 2, 3, 5, 6, 8
Here is what I tried
Sub SlicerTest()
With ActiveWorkbook.SlicerCaches("Slicer_rtytr")
Dim maxNumberOfDays As Long
maxNumberOfDays = 9 'I want to be able to identify the number of items programmatically but do not know how to do this
Dim fromDay As Long
fromDay = 3
Dim toDay As Long
toDay = 6
For i = 1 To maxNumberOfDays
If (i > fromDay And i < toDay) Then
.SlicerItems(CStr(i)).Selected = True
Else
.SlicerItems(CStr(i)).Selected = False
End If
Next i
End With
End Sub
The result should be that the slicer picks only 5 but it throws an error . I tried a regular 1,2,3,4,5,6,7,8 array and it works fine . I guess this one does not work because of missed values ?
This article explains what you need, and some.
https://paultebraak.wordpress.com/2012/02/24/accessing-the-slicer-through-vba/
The relevant bit:
Dim sC As SlicerCache
Dim SL As SlicerCacheLevel
Dim sI As SlicerItem
Set sC = ActiveWorkbook.SlicerCaches(“Slicer_Dates_Hie”)
Set SL = sC.SlicerCacheLevels(1)
Debug.Print “——————————————————————————“
For Each sI In SL.SlicerItems
Debug.Print “Caption –> ” & sI.Caption
Debug.Print “Value –> ” + CStr(sI.Value)
Debug.Print “Unique Name –> ” + sI.Name
Debug.Print “——————————————————————————“
Next
The reason that a normal array works (normal being quantified as containing 9 elements in an array in this context) is because you specify that you want to loop from 1 to 9 in this line here For i = 1 To maxNumberOfDays. In your example you only have 6 items so you'll hit an error by trying to access more items than are currently within the array.
I'm not too familiar with slicer objects unfortunately, but, to fix this issue you'll want to know exactly how many items are within your slicer. After a quick look at the documentation on silcers there doesn't appear to be a count property, however, there is a numberOfColumns property. If the column number correlates with how many objects you have (again not entirely sure that it does) then just assign:
maxNumberOfDays = ActiveWorkbook.SlicerCaches("Slicer_rtytr").numberOfColumns
If this does not work I would explore other options for figuring out the number of elements that will be within your array.
Related
In the small project I'm currently working on I have multiple Textboxes I control that all have very similar names (seg11, seg21, se31 etc.) that all use the same function. Is it possible to somehow call them all with a for loop?
I think it should look something like this but I'm not sure how I can make the different TextBox names work:
For n As Integer = 0 To 5
i = n
function(seg"n"1)
Next
You can get controls by with use parental control control function whose parameter can be the name of the desired control.
The correct way to string concat, use the & symbol, e.g: "seg" & n & "1"
The correct code for your problem:
For n As Integer = 0 To 5
Dim ctr As Control = Me.Controls("seg" & n & "1")
If ctr IsNot Nothing Then
Debug.WriteLine(ctr.Text)
End If
Next
I have tried so many methods from the removeduplicates, selections and scripting dictionaries and I cannot get this to work. I do understand there are multiple ways to do this but if any of you can help, that would be great.
I have one list of values that I am pulling through from another sheet (up to approx 80k rows) into cell B13 downwards. I am then trying to remove the duplicate values and cells so I am left with unique values which I can then use to perform lookups on other sheets.
Sub Address_Sage()
Dim dataBook As Workbook
Dim dict As Object
Dim Sage_Data As Worksheet, Address As Worksheet
Dim dataSource As Range, dataDest As Range
Dim sourceDataRowCount As Integer, index As Integer
Dim rowCount As Long
Dim strVal As String
Set dataBook = Application.ThisWorkbook
Set sheetSource = dataBook.Sheets("Sage_Data")
Set sheetDest = dataBook.Sheets("Address")
Set dict = CreateObject("Scripting.Dictionary")
Set dataSource = sheetSource.Range("A3", _
sheetSource.Range("A90000").End(xlUp))
sourceDataRowCount = dataSource.Rows.Count
Set dataDest = sheetDest.Range("B13", "B" & _
sourceDataRowCount)
For index = 1 To sourceDataRowCount
dataDest(index, 1).Value = dataSource(index, 1).Value
Next index
Sheets("Address").Select
rowCount = ActiveSheet.Range("B13").CurrentRegion.Rows.Count
Do While rowCount > 0
strVal = Address.Cells(rowCount, 1).Value2
If dict.exists(strVal) Then
ActiveSheet.Rows(rowCount).EntireRow.Delete
Else
dict.Add strVal, 0
End If
rowCount = rowCount - 1
Loop
'Set dict = Nothing
End Sub
It always gets stuck on strVal line. I have tried changing value2 to value1 as I only have column but no luck.
thank you
Not super experienced in VBA so I can't speak to exactly what you're doing and what your code is saying but I thought I'd share this with you. Last week I had to create a macrobook that returned the unique entries of electrical defects that different crews observed while on the job. I made a dictionary that read all of the entries in the spreadsheet and then later printed all of the unique entries. I'll post the code and try to walk you through it.
If .Range("A" & i) <> "" Then
If dict.Exists(data) Then
dict(data) = dict(data) + 1
Else
dict.Add Key:=Data, Item:="1"
End If
End If
So the code basically says if column A (i is simply an incrementer) is not empty, then we're going to read the entries of column A. Data is simply a variable and you would set it equal to the range of values you'd like read in the dictionary. Obviously dictionary keys are unique and cannot repeat, so the code asks if the key already exists in the dictionary. If so, we will add one to it's count or value. And if not we will add that key to the dictionary. At the end of your loop, your dictionary will have stored all unique entries and the number of times they appeared.
Now we can reference them or print them.
For r = 0 To dict.Count
Sheets("Results").Range("B" & iResults) = dict.Keys(r)
Sheets("Results").Range("C" & iResults) = dict(dict.Keys(r))
Next
This second piece of code is a loop from 0 to the number of entries in your dictionary. It starts at zero because the dictionary is stored like an array and VBA arrays are base zero. The first statement will print the unique keys for every r until there are no more entries in the dictionary. The second statement will print the value or items associated with them. It will be an integer value equal to the number of times that unique entry showed up in your data.
You can use this same method for other purposes as well, not just printing the data but referencing it and using it somewhere else. But I am sure you will find that the For-loop with dict.Keys(r) is the easiest way to run through your dictionary entries. Took me a few days to figure it out and it revolutionized my program. Hope this helps you out.
I'm trying to search for the number of times "Commodity" appears in the table column: Securities[Strategy]. I then want to take that number and resize a table (named: Commodity) on another worksheet accordingly. If it appears 6 times in column Securities[Strategy], the Commodity table should resize to 6 rows, and so on for any number.
I'm very new to VBA. When I run the following code nothing happens.
Sub AdjRow()
Dim Count1 As Integer
Count1 = Application.WorksheetFunction.CountIf(Range("Securities[Strategy]"), "Commodity")
Count1 = Count1 + 12
ActiveSheet.ListObjects("Commodity").Resize Range("$A$12:$J$" & Count1)
End Sub
To help with debugging you can either print key values to the immediate window using Debug.Print or to a messagebox using MsgBox. In this case though, I am curious if you get any error messages when you attempt to run the macro. Editing your code and attempting to run it, it runs fine when the result I get from the CountIf is larger than one, but aborts with an error when it is one or less. If the table you attempt to resize don't have headers, I assume the macro will run fine if CountIf is greater than zero.
Here is the the code, sample data, and output I got when attempting to debug your code. I ran the code 3 times, and had return values of 8, 1, and 2 from the CountIf-function. Note how I didn't get the third address for the listobject on the second run-through, this was because the code aborted when it tried to set the ListObject to only its headers (A2:J2).
Code
Option Explicit
Sub AdjRow()
Dim r As Range
Dim i As Long
Dim lo As ListObject
Set r = Sheet2.Range("Securities[Strategy]")
i = Application.WorksheetFunction.CountIf(r, "Test1")
i = i + 1
Set lo = Sheet1.ListObjects("Commodity")
Debug.Print i
Debug.Print r.Address
Debug.Print lo.Range.Address
lo.Resize Range("$A$2:$J$" & i)
Debug.Print lo.Range.Address
End Sub
Sheet1
Sheet2
Output to immediate window
9
$A$2:$A$10
$A$2:$J$9
$A$2:$J$9
2
$A$2:$A$10
$A$2:$J$9
3
$A$2:$A$11
$A$2:$J$9
$A$2:$J$3
I am trying to shuffle the items in a numbered list in MS Word 2010. The background for this question is that my wife is an English teacher who makes her tests using Word. Whenever she makes a test she also makes a second version by changing the order of the items in the numbered lists.
I am looking to either:
change the order of items in a numbered list that I select using the mouse, ie select the numbered list, push a button/shortcut and the list is shuffled
or
change the order of all numbered lists in the test, ie the macro looks for the start of a new numbered list, selects all items in the list, changes the order of the items and then moves over to the next numbered list.
All lists should keep the same formatting (ie start number) after using the code.
I tried for the first instance but did not succeed in determining the start and end line numbers of my selection.
Example:
Original:
===== Start: ========
Question 1 What answer is correct?
Answer A
Answer B
Answer C
Question 2 What answer is correct?
Answer D
Answer E
Answer F
Question 3 What answer is correct?
Answer G
Answer H
Answer J
======End========
The macro should create this:
======Start========
Question 1 What answer is correct?
Answer C
Answer A
Answer B
Question 2 What answer is correct?
Answer F
Answer E
Answer D
Question 3 What answer is correct?
Answer H
Answer J
Answer G
====End======
Since you are dealing with only 3 list items, it is pretty easy. Just swap any of the two items. The following code does the same.
For more than 3 items, you may have to repeat the logic of swapping more rows. But you should get the basic idea about how to go about it from this code.
Sub Shuffle()
Dim li As List, rng As Range, random As Integer
Randomize
For Each li In ThisDocument.Lists
' get either 1 or 2. We will swap this with the 3rd item
random = CInt(Rnd + 1)
' add a new paragraph as temporary place holder. This is so that we can keep the paragraph with its formatting intact.
Set rng = li.Range.Paragraphs.Add.Range
rng.FormattedText = li.Range.Paragraphs(random).Range.FormattedText
' swap the items
li.Range.Paragraphs(random).Range.FormattedText = li.Range.Paragraphs(3).Range.FormattedText
li.Range.Paragraphs(3).Range.FormattedText = rng.FormattedText
' remove the temporary paragraph we added
li.Range.Paragraphs.Last.Range.Delete
Next
End Sub
I slightly modified the code by Pradeep Kumar and this works like a charm, even with an unknown number of items per numbered list and so that it can be incorporated in the normal.dot template:
Sub Shuffle()
Dim li As List, rng As Range, random As Integer, nbr As Integer
Application.ScreenUpdating = False
Randomize
For Each li In ActiveDocument.Lists
nbr = li.CountNumberedItems
' Run along all items in list and swap with a random one from the same list
For a_counter = 1 To nbr
' Make sure the item is not swapped with itself, that would fail
again:
random = CInt((nbr - 1) * Rnd + 1)
If random = a_counter Then GoTo again
' add a new paragraph as temporary place holder. This is so that we can keep the paragraph with its formatting intact.
Set rng = li.Range.Paragraphs.Add.Range
rng.FormattedText = li.Range.Paragraphs(random).Range.FormattedText
' swap the items
li.Range.Paragraphs(random).Range.FormattedText = li.Range.Paragraphs(a_counter).Range.FormattedText
li.Range.Paragraphs(a_counter).Range.FormattedText = li.Range.Paragraphs(nbr + 1).Range.FormattedText
' remove the temporary paragraph we added
li.Range.Paragraphs(nbr + 1).Range.Delete
Next a_counter
Next
Application.ScreenUpdating = True
End Sub
I've been messing around with VBA in Excel a bit recently; and as a small project for myself, I'm trying to create a "draw names from a hat" sort of macro.
I began by generating a random number, and then choosing which entry from a Table (i.e. ListObject) would be selected using a case statement. The problem with this is that it only works of the number of Table entries is always the same.
So my question (probably a ridiculous one) is: is it possible at all to generate a dynamic 'Select Case' block, where the number of cases on the block is based on the number of entries in the Table?
Thanks.
-Sean
Edit: To clarify: what I am trying to do, exactly, is this:
I generate a random number, i, from 1 to n=10*(number of Table entries). After this, I want to display, in a cell, one of the table entries based on the random number.
Ideally, the code would work similarly to this:
if i = 1 to 10 then choose event 1
if i = 11 to 20 then choose event 2
if i = 21 to 30 then choose event 3
...
if i = (n-9) to n then choose event (n/10)
I hope this helps to clarify the goal of the code.
From our comments here is something you can use:
Sub random()
Dim used_rows As Integer
Dim random As Integer
Dim cell_array() As Integer
used_rows = Sheet1.UsedRange.Rows.Count
ReDim cell_array(used_rows)
For i = 1 To used_rows
cell_array(i - 1) = Cells(i, 1)
Next
random = Int(Rnd * (used_rows))
MsgBox cell_array(random)
End Sub
You can go ahead and change MsgBox to whatever you like, or set like Cell(1,4).Value = cell_array(random), or however you'd like to proceed. It will be based off the number of rows used. Though depending on how you implement your spreadsheet the code might have to be changed a bit.
Here's the update code from the suggestions from the comments. Also remember to use Randomize() in your form initialization or WorkBook Open functions.
Sub random()
Dim used_rows As Integer
Dim random As Integer
'Multiple ways to get the row count, this is just a simple one which will work for most implementations
used_rows = Sheet1.UsedRange.Rows.Count
random = Int(Rnd * (used_rows))
'I use the variable only for the reason that you might want to reference it later
MsgBox Cells(random, 1)
End Sub
This assumes that by "table" you mean "Table with a capital T", known in VBA as a ListObject:
Sub PickRandomTens()
Dim lo As Excel.ListObject
Dim ListRowsCount As Long
Dim RandomNumber As Long
Dim ListEvent As String
Dim Tens As Long
Set lo = ActiveSheet.ListObjects(1)
ListRowsCount = lo.DataBodyRange.Rows.Count
RandomNumber = Application.WorksheetFunction.RandBetween(10, ListRowsCount * 10)
ListEvent = lo.ListColumns("Data Column").DataBodyRange.Cells(Int(RandomNumber / 10))
MsgBox "Random number: " & RandomNumber & vbCrLf & _
"Event: " & ListEvent
End Sub