Printing from dynamic Excel list box - excel

I have a workbook that is a 'quick print' sheet for my workplace.
I am not very skilled with VBA, but I have found various bits from web searches that have given me mostly desired results.
This is the desired look of the sheet:
The column C and D is a List Box with the VBA code:
Private Sub Worksheet_Activate()
Dim Sh
Me.ListBoxSh.Clear
For Each Sh In ThisWorkbook.Sheets
Me.ListBoxSh.AddItem Sh.Name
Next Sh
End Sub
The print icon in D2 is linked to macro:
Sub Print_Sheets()
Dim i As Long, c As Long
Dim SheetArray() As String
With ActiveSheet.ListBoxSh
For i = 0 To .ListCount - 1
If .Selected(i) Then
ReDim Preserve SheetArray(c)
SheetArray(c) = .List(i)
c = c + 1
End If
Next i
Application.Dialogs(xlDialogPrinterSetup).Show
Worksheets(SheetArray()).PrintOut Copies:=1
End With
End Sub
and finally the sheet has following in ThisWorkbook in order to refresh the List Box and put the user on the correct page:
Private Sub Workbook_Open()
Sheets(2).Select
Sheets(1).Select
End Sub
The final bit of VBA seems to work as intended, but I included it anyway in case it could interfere with something (I don't think it can, but just to be sure).
The List Box populates as intended, but I can't get it to stay the width of the columns C:D, and the height of the populated cells in B, every time the workbook is opened the box will increase in size both to the right and down.
The print button works mostly as intended; when clicked it will prompt with available printers, and then OK to print, but cancelling still causes the document to print. It will also allow the printing of the "Please Select..." page - the name of the sheet this form is on - which I have tried to stop from happening but can't get it to work.
On the point of having the list box resize correctly, I have followed this answer but I can't figure out how to keep the size as the range, rather than an integer.
Edit: I have now figured out that I can use Me.ListBoxSh.Width = Range("C:D").Width to set the width the same as the desired columns, as well as Me.ListBoxSh.Height = Range("3:7").Height for the height in the image shown. However, I will be adding to this list and am not sure how to have the VBA code work as "Start in row 3 and continue until an unpopulated row".
On not being able to print the "Please Select..." sheet, I followed this guide and it didn't seem to do anything at all. I had changed the WsName = "Sheet1" line to read WsName = "Please Select..." also.
Any help would be appreciated.

Related

Can I dynamically count the number of times I reset an Excel Sheet?

Currently I have a reset button for my excel sheet which will clear the contents except the formulas I have. Is there a way to dynamically count how many times I "pressed" the reset button and clear contents?
This..
Public countR As Long
Sub Alternative1() 'This will return to 0 when you close the workbook
countR = countR + 1
MsgBox "The document has been cleared " & countR & " time(s)"
End Sub
or..
Sub Alternative2()
Dim rng As Range
Set rng = Range("A1") 'Change to some cell that isn't cleared by your code
rng.Value = rng.Value + 1
End Sub
and call them like..
Sub WhatYourCodeMaybeLooksLike()
Range("B1:C100").ClearContents
Alternative1
Alternative2
End Sub
The comment by reportgunner above is correct, but if you're asking for VBA options then look at module level variables.
Public x As Integer
Sub Button1_Click()
x = x + 1
MsgBox x
End Sub
x will begin as 0 when you open the workbook and will then be incremented each time Button1 is hit, in this case.
Slightly different are static variables which you can declare in the procedure with the code. Both will work fine in VBA.
The variable will often reset if your code hits errors during debugging. So the cell option might be preferable if you never want to lose track of the number.

Allow null input when retrieving data from multiselect listbox

I'm trying to create a simple worksheet-based form that will pull data from the selections into another sheet on the Excel workbook. This is my first time messing with Visual Basic and ActiveX controls and I don't have much programming experience, but with a lot of Googling I've managed to muddle through some so far.
The part in question: I have a couple of multiselect boxes that, with the click of a button, push the data into the spreadsheet, using this code:
Private Sub CommandButton1_Click()
Dim I As Long
Range("A10").Select
Range(Selection, Selection.End(xlToRight)).ClearContents
With Me.ListBox1
For I = 0 To .ListCount - 1
If .Selected(I) Then
Flg= True
txt = txt & "," & .List(I)
End If
Next
End With
If Flg Then
With Sheets("Sheet1")
.Range("A10").Value = Mid$(txt, 2)
End With
End If
txt=""
'Repeat for each listbox'
End Sub
As long as the user has selected at least one item in each listbox, this works fine to pull the data, and from there I can do what I need. But I don't want to require the user to click in each box (that is, I suppose I could force them to click a null selection if they don't want to select something in that box, but it would be easier to just have them not select anything at all). But (understandably) when nothing is selected in a given box, the code I pasted above returns run-time error 1004: No data was selected to parse.
How can I permit the user to make no selection in a box, and have the code just leave the associated cell blank when the data are retrieved?
Wow, after a couple of days of looking I finally found it. This is the code that worked for me:
Private Sub ListBox1_LostFocus()
Dim listItems As String, i As Long
With ListBox1
For i = 0 To .ListCount - 1
If .Selected(i) Then listItems = listItems & .List(i) & ", "
Next i
End With
If Len(listItems) > 0 Then
Range("A2") = Left(listItems, Len(listItems) - 2)
Else
Range("A2") = ""
End If
End Sub
And it came from this page: https://www.mrexcel.com/forum/excel-questions/584437-write-selections-excel-listbox-cell.html ...thanks to 'Marcelo Branco' for providing that answer 7 years ago!
EDIT - This really answers a separate question that I had (about retrieving the data automatically), but it seems to also work for the big question here, since when nothing is selected, the target cell is blank.

Excel Combo Box Refresh Dropdown?

Is there a way to refresh a combobox?
I have the following VBA code. The dropdown is populated, until the If statement where the list is cleared and populated with the matched items.
At this point, the dropdown list only shows a single item with a scroll bar. But If I close the pulldown and reopen, it's fully populated correctly.
Private Sub ComboBox_SiteName_Change()
ComboBox_SiteName.DropDown
Dim v As Variant, i As Long
With Me.ComboBox_SiteName
.Value = UCase(.Value)
If .Value <> "" And .ListIndex = -1 Then
v = Worksheets("Address").Range("Table5[[#All],[SITE NAME]]").Value
.Clear ' Clear all items
' Repopulate with matched items
For i = LBound(v, 1) To UBound(v, 1)
If LCase(v(i, 1)) Like "*" & LCase(.Value) & "*" Then
.AddItem v(i, 1)
End If
Next i
Else
' Repopulate with all items
.List = Worksheets("Address").Range("Table5[[#All],[SITE NAME]]").Value
End If
End With
End Sub
The ComboBox_Change function gets called as the user types in the combo box.. the dropdown box turns from a list into a single line with Up/Down arrows after the Clear and Repopulate matched items..
but if I close the dropdown portion and reopen it lists all the items without Up/Down arrows.
The .ListRows value = 8 by the way.
I would like a way for the dropdown potion to either close and reopen.. or a VBA function to refresh the dropdown portion, Without external buttons or controls Please
Getting the list to ONLY show values that matched the text typed by the user so far, was a nightmare. Below is what I wrote which works (but took me a while!)
Note that the MacthEntry Property of the combo box MUST be set to "2 - frmMatchEntryNone" for the code to work. (Other values cause the combo box .value property store the text of the first value that matches what the user typed, and the code relies on it storing what they typed.)
Also note, the trick to get around the behaviour you observed, ie the combo boxes list of values not being sized correctly, was to use the code lines:
LastActiveCell.Activate
ComboBox_SiteName.Activate
Also, the code will pick up any items on the list that have the letters typed by the user ANYWHERE in their text.
Anyway, here's my code:
Private Sub ComboBox_SiteName_GotFocus()
' When it first gets the focus ALWAYS refresh the list
' taking into acocunt what has been typed so far by the user
RePopulateList FilterString:=Me.ComboBox_SiteName.Value
Me.ComboBox_SiteName.DropDown
End Sub
' #4 Private Sub ComboBox_SiteName_Change()
Private Sub ComboBox_SiteName_Enter()
Dim LastActiveCell As Range
On Error GoTo err_Handler
Set LastActiveCell = ActiveCell
Application.ScreenUpdating = False
With Me.ComboBox_SiteName
If .Value = "" Then
' Used cleared the combo
' Repopulate will all values
RePopulateList
.DropDown
Else
' #4 reducdant
' LastActiveCell.Select
' .Activate
' ===========================================
' #4 new code
' CheckBox1 is another control on the form
' which can receive the focus and loose it without event firing
CheckBox1.SetFocus
' This will trigger the GotFocus event handler
' which will do a refresnh of the list
.SetFocus
' ===========================================
End If
End With
Application.ScreenUpdating = True
Exit Sub
err_Handler:
Application.ScreenUpdating = True
Err.Raise Err.Number, "", Err.Description
Exit Sub
Resume
End Sub
Private Sub RePopulateList(Optional FilterString As String = "")
Dim i As Long
Dim ValidValues() As Variant
' #2 range now refers to just the data cells
ValidValues = Worksheets("Address").Range("Table5[SITE NAME]").Value
With Me.ComboBox_SiteName
If FilterString = "" Then
' All all values
.List = ValidValues
Else
' #2: .List cannot be set to have no items.
' so remove all but one
.List = Array("Dummy Value")
' Only add values that match the FilterString parameter
For i = LBound(ValidValues, 1) To UBound(ValidValues, 1)
If LCase(ValidValues(i, 1)) Like "*" & LCase(FilterString) & "*" Then
.AddItem ValidValues(i, 1)
End If
Next i
' #2 add this line to remove the dummy item
.RemoveItem (0)
End If
End With
End Sub
Private Sub ComboBox_SiteName_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Application.ScreenUpdating = False
End Sub
======================================================================
You could: Replace all your code with this which should give acceptable functionality (as long a the data source is in alpha order), and it's easy! However, it doesn't quite do what you wanted.
Private Sub ComboBox_SiteName_GotFocus()
With Me.ComboBox_SiteName
.List = Worksheets("Address").Range("Table5[[#All],[SITE NAME]]").Value
End With
ComboBox_SiteName.DropDown
End Sub
Combo boxes can be set up to "filter as the user types" - so long as the data is in alphabetical order.
======================================================================
Note that in your code the following two lines cause the ComboBox_SiteName_Change event to start again. I suspect you need to add break points and debug you code more.
.Value = UCase(.Value)
.Clear ' Clear all items
Anyway, I hope this is job done.
this will be my first bounty if I get it, so please let me know if you need any more help. (I think it may be worth more than 50 points)
Harvey
================================================
PART 2:
To answer you comment issues:
(See the #2 tag in my code above)
To refer to a table column's data, excluding the header use:
=Table5[SITE NAME]
(This will be autogenerated when entering a formula if you click and drag over the data cells in a column).
The code has been altered accordlingly.
I used excel 2013 and 2010 and found that the .Activate event works in both.
See #3 for a minor change.
Please recopy all the code.
note that I introduced code to try and stop flickering using Application.ScreenUpdating, but it didn;t have any effect - I don't know why. I've left the code in so you can do further experiments should you need to.
NOTE the new procedure ComboBox_SiteName_KeyDown
================================================
PART 3:
To answer you comment issues:
It's a combo on a form ! - so make the change tagged with #4 above.
Harvey
Solved!
https://trumpexcel.com/excel-drop-down-list-with-search-suggestions/
You can do what is in the link with some modifications:
"ListFillRange" in combobox properties should be the last column (the one that is changing). If it is a userform the range will go under "RowSource".
And add this code:
Private Sub ComboBox1_Change()
Sheets("Where the data is").Range("B3") = Me.ComboBox1.Value
End Sub
Try changing the command from Change to DropButtonClick
This refreshes the list on a click of the drop down

Check box general selector and macro to show next three rows when one checkbox is selected

I am new to macros so I'm not sure this is possible in VBA.
I am trying to create a document where is composed with many mini tables made of 4 rows.
One row is the title which have a checkbox and will always be shown and three rows below where contains data that I only what to see when I select the relevant checkbox.
This document will have many mini tables hence many check boxes and I was wondering if there is a generic selector for checkboxes where I can apply the same macro.
I have seen the following macro, but this will apply only to one check box and I was wondering if there was a way to apply one for all checkboxes saying that if checkbox in row 4 is selected then show row 5,6 and 7. If checkbox in row 8 is selected then show rows 9,10,and 11 and so on....
Private Sub CheckBoxRow4_Click()
Rows("5:6:7").Hidden = CheckBoxRow4.Value
End Sub
See screenshot for a better idea.
It would also be appreciated if you could indicate how can I get those three rows below hidden by default when opening the document.
I am using Excel 2011 for Mac if that makes any difference.
Thank you in advance.
I'm sure there will be several approaches to this. My first thought goes to adding checkboxes, linking them all to a single macro. When activated, you have to do several things:
find out who is calling the sub (which checkbox);
find out where that specific checkbox is located (which row);
hide / unhide the rows below it.
1:
The name of the checkbox is easy. Application Caller will give you that.
2:
Location is the real problem here. I don't see a simple solution here, other then giving the checkboxes such specific names, that it is clear which row it is in. If you add a checkbox, you can give the name in the 'named range' inputfield. If you give it names that will specify the rows it must hide, it is even better. So something like:
HIDE_4_7 would indicate the checkbox must hide / unhide rows 4 to 7.
3:
Hiding the rows is now easy.
total solution:
Sub HideRows()
Dim cbName As String
Dim cbValue As Boolean
Dim s() As String
Dim firstRow As Long
Dim lastRow As Long
On Error Resume Next
cbName = Application.Caller
If Err.Number <> 0 Then Exit Sub 'sub is not called from an application object
cbValue = (ActiveSheet.CheckBoxes(cbName) = xlOn)
If Err.Number <> 0 Then Exit Sub 'sub is not called from a checkbox
On Error GoTo 0
s = Split(cbName, "_")
If s(LBound(s)) <> "HIDE" Then Exit Sub 'name of the shape is not valid
firstRow = Val(s(LBound(s) + 1))
lastRow = Val(s(LBound(s) + 2))
Sheets(1).Rows(firstRow & ":" & lastRow).Hidden = Not cbValue
End Sub
You would have to call the checkboxes HIDE_*firstrow*_*lastrow*, and link them to this sub. That works on my side.
EDIT
To hide all rows on opening, you could use the Workbook_Open sub (in the workbook code storage thingy). Something like this:
Private Sub Workbook_Open()
Dim shp As Shape
Dim s() As String
Dim firstRow As Long
Dim lastRow As Long
Dim cbValue As Boolean
For Each shp In Sheets(1).Shapes
Debug.Print shp.Name
s = Split(shp.Name, "_")
If s(LBound(s)) <> "HIDE" Then GoTo nextShp
'set checkbox off:
Sheets(1).CheckBoxes(shp.Name) = xlOff
firstRow = Val(s(LBound(s) + 1))
lastRow = Val(s(LBound(s) + 2))
Sheets(1).Rows(firstRow & ":" & lastRow).Hidden = True
nextShp:
Next shp
End Sub

Excel 2010 command button disappears

I'm developing an Excel 2010 workbook, in a manual formulas calculation mode.
(file -> options -> formulas -> Workbook calculation -> manual)
I have some command buttons in the sheet (ActiveX controls), and I set them to move and size with cells (right click on the button -> format control -> Properties -> move and size with text).
This is since I have some rows filtered out under some conditions, and I want the buttons placed in these rows to appear and disappear as well, according to the display mode of their hosting rows.
It all goes perfectly fine, till I save he worksheet when some of the rows (hence buttons) are filtered out (i.e. not displayed).
When I re-open the file again, and expand the filtered rows, the buttons don't show. When checking their properties I see that their visible property is True, but their height is 0, and this doesn't change when I un-filter their hosting rows.
I want to emphasize again that before saving the file - both filtering and un-filtering the buttons worked well.
Would much appreciate any help here.
OK so I get the same results either with ActiveX or Form Controls. For whatever reason, it seems the control's original height does not persist beyond the save & close.
Another option would be to simply clear the AutoFilter on the Workbook's Close and Save events. However, this probably is not what you want if you like to leave some filter(s) on when you save and re-open the file. It's probably possible to save the filter parameters in a hidden sheet or by direct manipulation of the VBE/VBA, but that seems like a LOT more trouble than it's worth. Then you could re-apply the filter(s) when you re-open the workbook.
Here is what code I suggest
NOTE: I relied on the worksheet's _Calculate event with a hidden CountA formula (setting, changing, or clearing the AutoFilter will trigger this event). I put the formula in E1 just so you can see what it looks like:
Since your application relies on Calculation = xlManual then this approach will not work exactly for you but in any case, the subroutine UpdateButtons could be re-used. You would need to tie it in to another event(s) or functions in your application, as needed.
Here is the code
Option Explicit
Private Sub UpdateButtons()
'## Assumes one button/shape in each row
' buttons are named/indexed correctly and
' the first button appears in A2
Dim rng As Range
Dim shp As Shape
Dim i As Long
Application.EnableEvents = False
'## use this to define the range of your filtered table
Set rng = Range("A1:A6")
'## Iterate the cells, I figure maybe do this backwards but not sure
' if that would really make a difference.
For i = rng.Rows.Count To 2 Step -1
Set shp = Nothing
On Error Resume Next
Set shp = Me.Shapes(i - 1)
On Error GoTo 0
If Not shp Is Nothing Then
DisplayButton Me.Shapes(i - 1), Range("A" & i)
End If
Next
Application.EnableEvents = True
End Sub
Private Sub DisplayButton(shp As Shape, r As Range)
'# This subroutine manipulates the shape's size & location
shp.Top = r.Top
shp.TopLeftCell = r.Address
shp.Height = r.Height
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
MsgBox "_Change"
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
''## Assumes one button/shape in each row
'' buttons are named/indexed correctly and
'' the first button appears in A2
'Dim rng As Range
'Dim shp As Shape
'Dim i As Long
'
''## Uncomment this line if you want an annoying message every time
''MsgBox "Refreshing Command Buttons!"
'
'Application.EnableEvents = False
''## use this to define the range of your filtered table
'Set rng = Range("A1:A6")
'
''## Iterate the cells, I figure maybe do this backwards but not sure
'' if that would really make a difference.
'For i = rng.Rows.Count To 2 Step -1
' Set shp = Nothing
' On Error Resume Next
' Set shp = Me.Shapes(i - 1)
' On Error GoTo 0
'
' If Not shp Is Nothing Then
' DisplayButton Me.Shapes(i - 1), Range("A" & i)
' End If
'Next
'
'Application.EnableEvents = True
End Sub
For Another option See this article. You can re-purpose existing commands with RibbonXML customization. While this article is geared towards C# and Visual Studio it's possible to do it with the CustomUI Editor.
I had a similar problem with buttons disapearing (moving on upper left corner) when removing filters.
A solution I found was to add a row above the columns headers so that buttons were still appearing at the top of the columns but were not touching the row where filters were placed.
Adding / removing filters stop interfering with buttons' positions.
I had a similar problem where form buttons appear to work fine, but then disappear after saving and reopening the workbook. Specifically this happened when the form button where part of hidden rows (done using vba code).
Seems like a real bug, although I don't know where the link is.
By changing the form buttons to ActiveX buttons, the buttons stopped disappearing, but started moving/bunching to the top of the screen when the rows were hidden. I just added some vba to re-position the buttons (e.g. CommandButton1.Top = Range(A12:A12).Top --> moves the ActiveX command button to the 12th row).

Resources