Print keeps doing double sided (I only want one per page) - vba

I have built the following VBA code:
Option Explicit
Private Sub PrintBtn_Click()
Worksheets.PrintOut from:=FromBox.Value, to:=ToBox.Value, Copies:=Copies.Value
End Sub
Private Sub CloseBtn_Click()
Unload Me
End Sub
Private Sub UserForm_Initialize()
Copies.Value = 1
FromBox.Value = 1
Dim i As Long
For i = 1 To ActiveWorkbook.Sheets.Count
SheetBox.Value = SheetBox.Value & i & " - " & ActiveWorkbook.Sheets(i).Name & vbCrLf
Next i
ToBox.Value = i - 1
End Sub
Basically populates a userform with the names of each worksheet in excel. There's a from box and a to box, and I'm trying to give the user an ability to print out each page individually. It works, the print function works, but rather than printing out each one on a separate page, after the first page it makes everything double sided!
Basically I want to print out sheets X through Y without having it be double sided. The usual print dialog box does not work and also makes it double sided. Perhaps it is a problem with the worksheets themselves, but I do not know what setting I can focus on or change to do so.

Related

PowerPoint How to Run Macro and Hyperlink at The Same Time?

I'm trying to make a choose your own type of game in powerpoint. The game includes a point system that I did using a macro when the user is clicks an option. I also need a hyperlink to jump to the right slide in accordance to the option that was picked.
I tried creating 1 macro for every button, assigning where to slide to jump to, but this becomes solution way too messy since, by the end of the game, there would be hundreds of buttons = hundreds of macro.
Dim numCorrect As Integer
Dim numIncorrect As Integer
Dim userName As String
Dim printableSlideNum As Long 'ADDED
Sub GetStarted()
Initialize
ActivePresentation.SlideShowWindow.View.Next
End Sub
Sub Initialize()
numCorrect = 0
numIncorrect = 0
ActivePresentation.SlideShowWindow.View.Next
End Sub
Sub Right()
numCorrect = numCorrect + 10
End Sub
Sub Wrong()
numIncorrect = numIncorrect + 25
End Sub
Sub Feedback()
MsgBox "You spent " & numCorrect + numIncorrect & " minutes to solve the issue" & vbCr & _
"Out of the " & numCorrect + numIncorrect & ", you wasted " & numIncorrect & " minutes by choosing the wrong options"
End Sub
Sub JumpTo(lSlideIndex As Long)
SlideShowWindows(1).View.GotoSlide (lSlideIndex)
End Sub
Sub ONEA()
Right
JumpTo 6
End Sub
I had an idea of creating a macro that jumped to a slide number according to the name of the shape, but don't know whether it is possible or not.
Example: option B jumps to slide 60
the shape name would be 60
the vba will match the shape name and jumps to slide 60
Any help/ideas for this is appreciated!
Note: my VBA skills is essentially zero.
To name your shape see How to name an object within a PowerPoint slide?
Sub JumpToSlide(oShp As Shape)
lSlideIndex = CLng(oShp.Name)
SlideShowWindows(1).View.GotoSlide (lSlideIndex)
End Sub
To assign this macro to the shape you can right-click on the shape --> Hyperlink --> Run a Macro --> Select "JumpToSlide"

Advanced customization of InputBox edit control

So I have some basic VBA code:
Sub Test()
' Set error handler
On Error GoTo ErrorHandler
Dim strElevation As String
strElevation = InputBox("Enter elevation difference:", "Create Cross Lines", 0.5)
Exit Sub
ErrorHandler:
Call ReportError("Test")
End Sub
And it looks fine:
Is it possible to extend this so that the edit box will only allow a numeric value to 2 decimal places? Or is it simply too much work?
I know how to format text itself, eg: Format("1234.5678", "#.00"). But can the actual edit control have any customization itself?
You basically have three options here... In order of difficulty:
1. Validate the input
This uses the native InputBox() function as you have in your code sample above. You can return the value into a string variable, then do your validation at that point to make sure the data is formatted the way you want. If it doesn't pass, then display the input box again.
2. Custom VBA form
If you create your own VBA User Form, you can customize the text box to use a specific format, and perform the validation before the form accepts the input and closes. This is probably the most user-friendly approach, but involves a little more code than the first method.
Example:
Create sample VBA form with two input boxes and a command button. Name them txtDiff1, txtDiff2, and cmdOK respectively.
Double-click one of the controls, and add the following code to the code module behind the form:
Option Explicit
Private Sub cmdOK_Click()
MyElevationDifference = txtDiff1 ' (or txtDiff2)
Unload Me
End Sub
Private Sub txtDiff1_AfterUpdate()
Dim dblValue As Double
If IsNumeric(txtDiff1) Then
' Determine rounded amount
dblValue = Round(txtDiff1, 2)
' Automatically round the value
If dblValue <> CDbl(txtDiff1) Then txtDiff1 = dblValue
Else
MsgBox "Please enter a numeric value", vbExclamation
End If
End Sub
Private Sub txtDiff2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
Dim dblValue As Double
If IsNumeric(txtDiff2) Then
' Determine rounded amount
dblValue = Round(txtDiff2, 2)
' Require a max of 2 decimal places
If dblValue <> CDbl(txtDiff2) Then
Cancel = True
MsgBox "Please only use 2 decimal places", vbExclamation
End If
Else
MsgBox "Please enter a numeric value", vbExclamation
' Cancel change
Cancel = True
End If
End Sub
Paste the following into a regular code module. (This is how you can get the input in your main code through the custom form. Essentially the form assigns a value to the global variable, and you reference that after showing the form.)
Option Explicit
Public MyElevationDifference As Double
Public Sub GetElevationDifference()
UserForm1.Show
MsgBox "Elevation difference: " & MyElevationDifference, vbInformation
End Sub
Now when you run GetElevationDifference(), you will see a couple different approaches demonstrated on the user form. The first text box automatically rounds the input, while the second text box does not allow the user to continue unless they correct the input to use two decimal places or less.
Of course you will want to add some error handling and make the form look nice, but this gives you a simple example of how to use a VBA form to get user input. They involve a little more code, but obviously provide a huge level of additional flexibility over the simple InputBox() function.
3. Windows API calls
Just for completeness, there are ways to use Windows API calls to actually affect the controls on an input box, but this would end up being far more complex than the first two approaches, and I would not recommend it for something like this.
this is how you can restrict to input box to allow only numeric values:
strElevation = Application.InputBox(prompt:="Enter elevation difference:", Title:="Create Cross Lines", Default:=0.5, Type:=1)
https://msdn.microsoft.com/en-us/vba/excel-vba/articles/application-inputbox-method-excel
To validate the lenght, you can use the following code:
Do
strElevation = Application.InputBox(prompt:="Enter elevation difference:", Title:="Create Cross Lines", Default:=0.5, Type:=1)
If Len(strElevation) > 2 Then MsgBox "You typed in too many characters... 2 maximum!"
Loop While Len(strElevation) > 2
Private Sub TextBox1_AfterUpdate()
If InStr(1, Me.TextBox1.Value, ".") > 0 Then
If Len(Mid(Me.TextBox1.Value, _
InStr(1, Me.TextBox1.Value, "."), _
Len(Me.TextBox1.Value) - InStr(1, Me.TextBox1.Value, "."))) > 2 Then
Me.TextBox1.SetFocus
MsgBox "cannot have more than 2 decimal places"
End If
End If
End Sub
Apply to your situation but this gets you there
Sub Test()
' Set error handler
On Error GoTo ErrorHandler
Dim strElevation As String
strElevation = InputBox("Enter elevation difference:", "Create Cross Lines", 0.5)
If InStr(1, strElevation, ".") > 0 Then
If Len(Mid(strElevation, InStr(1, strElevation, "."), Len(strElevation) - InStr(1, strElevation, "."))) > 2 Then
MsgBox "cannot have more than 2 decimal places"
End If
End If
Exit Sub
ErrorHandler:
Call ReportError("Test")
End Subc

VBA - Error While Programming a Class to Operate all Checkboxes on Userform

Here is a bit of background on what I'm trying to do: I'm creating a userform to track Inventory items and prices, using checkboxes in a multipage object. The clerk checks off everything put into an order and uses a submit button, which will take some actions.
In order for the project not to require a coding person every time Inventory items change, the checkboxes are being dynamically generated when the userform is activated, from cell values on an Inventory sheet. The clerks just adjust the Inventory sheet and the form automatically adjusts for them.
This is my code to dynamically create all the checkboxes (currently this form can accommodate up to 160 possible checkboxes), in case this is effecting my issue (side note, each tab on the multipage has a frame on it, and all checkboxes are within the frame, so I could change background colors, the frame in this example being titled "frmreg"):
Sub StoreFrmRegCheckboxGenerator()
'Works with the store userform
Dim curColumn As Long
Dim LastRow As Long
Dim i As Long
Dim chkBox As msforms.CheckBox
'This sub dynamically creates checkboxes on the Regular Items tab based
'on values in Column A of the Inventory sheet
curColumn = 1 'Set your column index here
LastRow = Worksheets("Inventory").Cells(Rows.Count, curColumn).End(xlUp).Row
For i = 2 To 9
If Worksheets("Inventory").Cells(i, curColumn).Value <> "" Then
Set chkBox = store.frmreg.Controls.Add("Forms.CheckBox.1", "CheckBox_" & i)
chkBox.Caption = Worksheets("Inventory").Cells(i, curColumn).Value & " - $" & Worksheets("Inventory").Cells(i, curColumn).Offset(0, 1).Value
chkBox.AutoSize = True
chkBox.WordWrap = True
chkBox.Left = 5
chkBox.Top = 1 + ((i - 1) * 25)
End If
Next i
'Cut some code out here identical to this previous section, but for the rest of the cells in column A up to Row 33, in blocks of 8
End Sub
The above code is in the Userform_Initialize sub, and it works perfectly.
However, since the number of checkboxes is not static, and can be as many as 160, I'm trying to write one sub to take the same set of actions any time any checkbox is clicked.
The closest solution I've found is from this question: Excel Macro Userform - single code handling multiple checkboxes, from sous2817.
Here is his code that I'm trying to use:
In a new class module:
Option Explicit
Public WithEvents aCheckBox As msforms.CheckBox
Private Sub aCheckBox_Click()
MsgBox aCheckBox.Name & " was clicked" & vbCrLf & vbCrLf & _
"Its Checked State is currently " & aCheckBox.Value, vbInformation + vbOKOnly, _
"Check Box # & State"
End Sub
The "store" userform, at the top, right under Option Explicit:
Dim myCheckBoxes() As clsUFCheckBox
At the bottom of the Userform_Initialize sub, AFTER I call the all the subs that dynamically create all the checkboxes:
Dim ctl As Object, pointer As Long
ReDim myCheckBoxes(1 To Me.Controls.Count)
For Each ctl In Me.Controls
If TypeName(ctl) = "CheckBox" Then
pointer = pointer + 1
Set myCheckBoxes(pointer) = New clsUFCheckBox
Set myCheckBoxes(pointer).aCheckBox = ctl
End If
Next ctl
ReDim Preserve myCheckBoxes(1 To pointer)
When I try to open the userform I get this error:
"Compile Error: User-defined type not defined"
Pointing to this line:
Dim myCheckBoxes() As clsUFCheckBox
Am I missing a library reference? I haven't been able to figure this out.

Reading checkbox values with a loop (Microsoft Word VBA)

I'm current trying to write a macro (VBA in Word) that will compile information from a collection of documents into a single document.
I order to do this I have a list of ~20 checkboxes that will determine which documents I want to include in the compilation. My issue is that when writing the macro, I can't figure out a way of checking the state of each checkbox on my list without re-writing the same block of code 20 times, only changing the name of the checkbox. eg CB1 to CB2, CB3 CB4 etc. each time.
This is the block of code in question. It does work if I rewrite it multiple times for the changing check box number but I would prefer it in a loop so the code is more compact and robust:
If ThisDocument.CB1.Value = True Then
Documents.Open(directory).Activate
Selection.WholeStory
Selection.Copy
Documents(NewFile).Activate
Selection.Paste
Documents("file.docx").Close
End If
Ideally I would like to have the check box named something like CBn, where n is a variable that I can redefine at the end of each loop.
There's no option for directly referring to a control by its name - you can wrap that up in a function though:
Sub Tester()
Dim x As Long, cb As Object
For x = 1 To 3
'find the checkbox
Set cb = ControlByName("CB" & x, ThisDocument)
'check we got something back
If Not cb Is Nothing Then
Debug.Print "CB" & x & " is " & cb.Value
End If
Next x
End Sub
Function ControlByName(sName, doc As Document) As Object
Dim obj
For Each obj In doc.InlineShapes
If obj.OLEFormat.Object.Name = sName Then
Set ControlByName = obj.OLEFormat.Object
Exit Function
End If
Next obj
End Function

VBA Userform with Textbox - formatting the text

so I'm very new to VBA. I've created a very simple template that when opened, gives me a form to fill out which will insert text into a document through a commandbutton.
I'm trying to take it a step further a bit but am not sure how to go about bringing the code together. To insert the text, I'm using the bookmark feature. On my form, I have 4 Textboxes that act as options. If all 4 are filled in, the text looks like:
Option1Option2Option3Option4
I need it to look like:
Option1, Option2, Option3 and Option4
Not only that but I would like it so that the "and" is added depending on how many textboxes are filled in. For example, if I only have the first two filled it, I need it to look like:
Option1 and Option2
Does that make sense? Below is how it's structured currently. I would appreciate any pointers in moving forward.
Private Sub cmdSubmit_Click()
Application.ScreenUpdating = False
With ActiveDocument
.Bookmarks("Program1").Range.Text = TextBox1.Value
.Bookmarks("Program2").Range.Text = TextBox2.Value
.Bookmarks("Program3").Range.Text = TextBox3.Value
.Bookmarks("program4").Range.Text = TextBox4.Value
End With
Application.ScreenUpdating = True
Unload Me
End Sub
If these bookmarks are contiguous, there is no need for four bookmarks. Add the following module-level variables:
Private s As String, hasAnd As Boolean
Create a Sub which prepends the text of a textbox to the private variable, inserting a comma or and as appropriate:
Private Sub AppendText(txt As TextBox)
If Len(txt.Text) = 0 Then Exit Sub
If Len(s) = 0 Then
s = txt.Text
ElseIf Not hasAnd Then
hasAnd = True
s = txt.Text & " and " & s
Else
s = txt.Text & ", " & s
End If
End Sub
Call the subprocedure for each textbox in reverse order:
AppendText TextBox4
AppendText TextBox3
AppendText TextBox2
AppendText TextBox1
Then, use the value of s as the text of the bookmark:
ActiveDocument.Bookmarks("Program1").Range.Text = s