Keep Listbox at top of Scrolling Worksheet [duplicate] - excel

I have an excel workbook with two shapes on Sheet1 like below
My Requirement is when the user is navigating towards right side of sheet i.e. Towards headers24, header25 and so on ,I want the two shapes on the sheet to move towards the right side with the user.
Can someone Please suggests any ideas for this.
Thanks

Try this.. yep, its easy..
Place this code in the worksheet module where the shapes exist.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
With ActiveSheet.Shapes(1)
.Left = ActiveWindow.VisibleRange(2, 2).Left
.Top = ActiveWindow.VisibleRange(2, 2).Top
End With
End Sub
The coordinate (2, 2) is where you want the shape to be fixed at as you scroll along with the keyboard.
But, it would be annoying to work without the scroll bar on a huge worksheet. so alternatively I think you can use refresh ontime, place this code in a Module
Private eTime
Sub ScreenRefresh()
With ThisWorkbook.Worksheets("Sheet1").Shapes(1)
.Left = ThisWorkbook.Windows(1).VisibleRange(2, 2).Left
.Top = ThisWorkbook.Windows(1).VisibleRange(2, 2).Top
End With
End Sub
Sub StartTimedRefresh()
Call ScreenRefresh
eTime = Now + TimeValue("00:00:01")
Application.OnTime eTime, "StartTimedRefresh"
End Sub
Sub StopTimer()
Application.OnTime eTime, "StartTimedRefresh", , False
End Sub
And the following code in Sheet1 (where the shapes are in)
Private Sub Worksheet_Activate()
Call StartTimedRefresh
End Sub
Private Sub Worksheet_Deactivate()
Call StopTimer
End Sub

First create the shape:
Sub Creator()
Dim shp As Shape
Set shp = ActiveSheet.Shapes.AddShape(1, 100, 10, 60, 60)
shp.TextFrame.Characters.Text = "I will follow"
shp.Name = "MyButton"
End Sub
Then in the worksheet code area:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim sh As Shape, r As Range
Set sh = ActiveSheet.Shapes("MyButton")
Set r = ActiveCell
sh.Top = r.Offset(-1, -2).Top
sh.Left = r.Offset(-1, -2).Left
End Sub
If you move the active cell back and forth, the box will move with it.
Note:
This is only demo code. You still need to:
add protection to prevent trying to move the Shape "off-screen"
setting the proper offsets from ActiveCell based on the size of the Shape

Related

Controlling dynamically created controls on a userform in VBA excel

I have created a multipage user form which dynamically populates with a set of identical frames and each of them has 2 option buttons based on previous user selections. I am trying to check if at least one of the option buttons is selected within each frame but don't seem to access the option buttons in code even through I know what their names will be. I will then be transferring the selection to a worksheet so need to be able to see what they have selected. Any help would be appreciated, I use VBA for excel infrequently so its always a struggle to be honest.
I'm getting closer, I've used this code of another post and changed it slightly while I trial what I am doing. Getting there slowly. :)
I'm not sure what some of the Class modules part is doing but its working.
Forms: Userform1
Option Explicit
Friend Sub OptionButtonSngClick(o As MSForms.OptionButton)
Dim cControlCheck As MSForms.Control
Dim cControlCheck1 As MSForms.Control
Dim cControlFrame As MSForms.Control
Dim strName As String
If Left(o.Name, 2) = "qN" Then
o.BackColor = RGB(256, 0, 0)
ElseIf Left(o.Name, 2) = "qY" Then
o.BackColor = RGB(0, 256, 0)
End If
For Each cControlCheck In UserForm1.Controls
If TypeName(cControlCheck) = "Frame" Then
For Each cControlCheck1 In Me.Controls(cControlCheck.Name).Controls
If TypeName(cControlCheck1) = "OptionButton" Then
If cControlCheck1 = False Then
cControlCheck1.BackColor = RGB(240, 240, 240)
End If
End If
Next
End If
Next
End Sub
Friend Sub cmdCheck_Click()
Dim cControlCheck2 As MSForms.Control
Dim cControlCheck3 As MSForms.Control
Dim cCollection As Collection
Set cCollection = New Collection
For Each cControlCheck2 In UserForm1.Controls
If TypeName(cControlCheck2) = "Frame" Then
For Each cControlCheck3 In Me.Controls(cControlCheck2.Name).Controls
If TypeName(cControlCheck3) = "OptionButton" Then
cCollection.Add cControlCheck3
End If
Next
End If
Next
If cCollection(1).Value = False And cCollection(2).Value = False Then
MsgBox ("Make a selection")
End If
End Sub
Class Module: OPtionButtonEvents
Option Explicit
Private WithEvents ob As MSForms.OptionButton
Private CallBackParent As UserForm1
Private CallBackParent1 As UserForm1
Private Sub ob_Change()
End Sub
Private Sub ob_Click()
Call CallBackParent.OptionButtonSngClick(ob)
End Sub
Private Sub ob_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Call CallBackParent.OptionButtonDblClick(ob)
End Sub
Friend Sub WatchControl(oControl As MSForms.OptionButton, oParent As UserForm1)
Set ob = oControl
Set CallBackParent = oParent
End Sub

Picture Group set to Range

Apologies another noob question. I have been tasked with writing a document within excel, the front cover has a lot of images on it and i have grouped these images together. As there is a risk that the user could move this group. I want to set it so each time that sheet is selected it moves back to its original location. I have looked over the web and i can't seem to find anything for a group of images.
I have tried this and it doesnt work at all. :(
Private Sub Worksheet_Activate()
Dim PicGroup As GroupShapes
With Range("A1")
PicGroup.Name = "HeaderGrp"
PicGroup.Visible = True
PicGroup.Top = .Top
PicGroup.Left = .Left
End With
End Sub
So my group of images I have called HeaderGrp I have put this on Activate Worksheet in VBA and i want this to always move or fix to cells A1.
I would also love this to fit to the page width and length if anyone knows how to do that.
Snapshot of what i would like: -
1) on sheet selection, image group moves to the correct location.
2) image group auto adjusts to page width and height.
Thank you in advance,
This works for me. Pictures appear to be treated as a type of Shape.
Private Sub Worksheet_Activate()
Dim p As Shape
With activesheet
Set p = .Shapes("Pics") 'name
p.Top = .Range("a1").Top
p.Left = .Range("a1").Left
End With
End Sub
This piece of code should get your grouped images:
Option Explicit
Private Sub Worksheet_Activate()
Dim shp As Shape
Dim PicGroup As GroupShapes
'loop through all your shapes
For Each shp In Me.Shapes
'if the shape is grouped then
'set your PicGroup variable
'and exit the loop
If shp.Type = msoGroup Then
Set PicGroup = shp.GroupItems
Exit For
End If
Next shp
With Range("A1")
PicGroup.Name = "HeaderGrp"
PicGroup.Visible = True
PicGroup.Top = .Top
PicGroup.Left = .Left
End With
End Sub

I want to auto-run my macro when opening the excel file

I want to auto-run this private sub when opening the excel sheet.
I tried using Private Sub Workbook_Open() method but as the first private sub does not have a name, it does not work.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet: Set ws = Sheets("Budget- Reporting")
If Range("W6").Value = 0 Then
HideFG
Else
HideF
End If
End Sub
Sub HideF()
'
' HideF Macro
'
'
For i = 1 To ActiveSheet.Shapes.Count
ActiveSheet.Shapes(i).Visible = msoTrue
Next i
ActiveSheet.Shapes.Range(Array("F")).Visible = msoFalse
Application.CommandBars("Selection").Visible = False
End Sub
Sub HideFG()
'
' HideFG Macro
'
'
For i = 1 To ActiveSheet.Shapes.Count
ActiveSheet.Shapes(i).Visible = msoTrue
Next i
ActiveSheet.Shapes.Range(Array("FG")).Visible = msoFalse
Application.CommandBars("Selection").Visible = False
End Sub
I hope that it automatically checks cell W16 when opening the excel file and carries on with HideF macro or HideFG macro. Currently, the two macros run once you actual type on the cell after opening the file.
the easiest way is to use the default Module "ThisWorkbook" which gets executed when opening the excel file. You can find it within your VBA Project Explorer on the left side of the window.
Just take the sub you want to execute and copy it into the space.
Its explained in great detail here:
https://support.office.com/en-us/article/automatically-run-a-macro-when-opening-a-workbook-1e55959b-e077-4c88-a696-c3017600db44
If it is necessary for your usecase this can help you to call a private sub:
Private Sub PrivateCallDemo()
'Module2
Application.Run "Module1.Worksheet_Change"
End Sub
This way your actual Sub could stay in another Module.
You have a few problems. First you don't want Worksheet_Change(ByVal Target As Range)
as that is for events triggers on changes to the workbook, you want Workbook_Open(). This gets stored under ThisWorkbook not a separate module/sheet.
Here is working code, I commented out your ws declaration for testing.
Private Sub Workbook_Open()
'Dim ws As Worksheet: Set ws = Sheets("Budget- Reporting")
If Range("W6").Value = 0 Then
HideFG
Else
HideF
End If
End Sub
Sub HideF()
MsgBox "HideF"
End Sub
Sub HideFG()
MsgBox "HideFG"
End Sub
Here is a screenshot of my editor.
G.M. posted a great resource as well found here --> https://support.office.com/en-us/article/automatically-run-a-macro-when-opening-a-workbook-1e55959b-e077-4c88-a696-c3017600db44
I just put the modules in the same spot for the screenshot, but you can put them separately and still use the Call HideFG method if you want to store your modules separately from the workbook_open event as I would want to.

How to send variables between a sheet and book?

Ultimately, I'm trying to highlight cells when focus moves away from a workbook.
Here's my code (In ThisWorkbook):
Public s As Range
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
s = Selection
End Sub
Private Sub Workbook_Deactivate()
s.Interior.ColorIndex = xlColorIndexNone
s.Interior.Color = RGB(0, 0, 0)
End Sub
Private Sub Workbook_Activate()
s.Interior.ColorIndex = xlColorIndexNone
s.Interior.Color = RGB(100, 204, 204) ' Blue
End Sub
But I'm getting an error on the first s.Interior.ColorIndex encountered:
Object variable or With block variable not set
Here's some images of my env:
Sheet1
ThisWorkbook (Error highlighted):
There are a few issues:
1) In order to be visible throughout the project, Public variable declarations must be in a standard code module. Thus the line
Public s As Range
shouldn't be in ThisWorkbook but should be in a standard code module.
2) s = Selection should be changed to Set s = Selection
3) The sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Set s = Selection
End Sub
Should be in a sheet module (and repeated for every sheet that you want this for). It isn't a syntax error to have it in ThisWorkbook, but it won't work as intended.
4) It is dangerous to assume that s is defined whenever the activate or deactivate is triggered. You should guard against that. Something like:
Private Sub Workbook_Activate()
If s Is Nothing Then
Set s = Selection
Exit Sub
End If
s.Interior.ColorIndex = xlColorIndexNone
s.Interior.Color = RGB(100, 204, 204) ' Blue
End Sub
With something similar for Deactivate.

Buttons that change color of a Range and a DblClick to revert the changes

I am looking to edit my current code as it is very long winded but if need be I can stick with it. My current code is simply repeated on each button as it runs through ActiveX buttons (these buttons must stay). Undo action is preferred but changing the colour back using RGB is a viable option.
My coding is as follows:
Private Sub btn3_Click()
Sheet1.Range("A84:J84").Interior.ColorIndex = 16
End Sub
This changes the cell range to a grey colour succesfully, I now need a double click to undo the action or something that will change the colours back to the original colour; I made two attempts.
Using undo function.
Private Sub btn3_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
End Sub
Then I tried a different method and went to change the colour.
Private Sub btn3_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Dim color_index As Long
color_index = 10
Sheet1.Range("A84:J84").Interior.Color(color_index) = RGB(153, 153, 255)
End Sub
End result was unsuccessful in both attempts.
Neither of these worked and would like a 'work around' or to fix my errors, any ideas accepted but I must keep buttons I cannot use 'Cell Selection'.
EDIT
If possible there my be an array method useable, I am not good with using ActiveX controls so any advice will most likely be very useful.
My workbook explaining what btn3 represents.
http://i.stack.imgur.com/35p2f.png
There's no easy way to do Application.Undo to undo the results of a macro-performed operation. You either need to create a cache/copy of the data and revert to that, or you need to formulate a way to "undo" in a custom function.
In any case, the error in your second method, this line:
Sheet1.Range("A84:J84").Interior.Color(color_index) = RGB(153, 153, 255)
Could eeither be changed to:
Sheet1.Range("A84:J84").Interior.ColorIndex = color_index
Or:
Sheet1.Range("A84:J84").Interior.Color = RGB(153, 153, 153)
Alternatively, you can do a custom undo function, something like this:
'## Module level variable
Dim previousColor As Long
Sub btn3_Click()
'## stores the current ColorIndex property of the range
' (assumes all cells have the same color)
previousColor = Sheet1.Range("A84:J84").Interior.ColorIndex
'## Applies the new color:
Sheet1.Range("A84:J84").Interior.ColorIndex = 16
End Sub
Sub btn3_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Sheet1.Range("A84:J84").Interior.ColorIndex = previousColor
End Sub
Further, you inquire:
as I updated is there a way to do this on a mass scale as I have 60+ 'buttons'...
Yes. Ensure firstly that all of the buttons call the same procedures. Then, modify the procedures for each button like below. NOTE I can't get the double-click to work without also invoking the single-click event, first, which has the undesired effect of not being able to "store" the previous color for the range. You may be able to add some conditional logic, for the time being I've hard-coded so the "undo" function will revert to no color at all:
Dim previousColor As Long '
Private Sub CommandButton1_Click()
Debug.Print "click"
Call changeColor(CommandButton1)
End Sub
Private Sub CommandButton1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Debug.Print "dbl click"
Call undoChangeColor(CommandButton1)
End Sub
Private Sub CommandButton2_Click()
Debug.Print "click"
Call changeColor(CommandButton2)
End Sub
Private Sub CommandButton2_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Debug.Print "dbl click"
Call undoChangeColor(CommandButton2)
End Sub
Private Sub changeColor(btn As MSForms.CommandButton)
'Assumes all cells are same color initially
previousColor = -4142 '(none) 'Sheet1.Range("A84:J84").Interior.ColorIndex
'Get the row corresponding with each button:
Dim rng As Range
Set rng = Sheet1.Range("A" & btn.TopLeftCell.Row).Resize(1, 11)
rng.Interior.ColorIndex = 16 'Modify as needed
'you could assign the RGB() here
End Sub
Private Sub undoChangeColor(btn As MSForms.CommandButton)
'Get the row corresponding with each button:
Dim rng As Range
Set rng = Sheet1.Range("A" & btn.TopLeftCell.Row).Resize(1, 11)
rng.Interior.ColorIndex = previousColor
End Sub

Resources