Excel: How to retrieve the frozen range of the Worksheet programmatically? - vb.net

I'm using VSTO to build an Excel add-in.
I want to build two functions. The first one, stores the frozen range at my Excel.Range variable called RNG and then unfreeze panes, using the following command.
Globals.ThisAddIn.Application.ActiveWindow.FreezePanes = False
The second function selects the range and freezes it again. With the following
RNG.Select()
Globals.ThisAddIn.Application.ActiveWindow.FreezePanes = True
What i don't know is how to store the frozen range before unfreeze the window.
Does someone can help me with doing this, or knows some other workaround?
Thanks.

With #Byron 's help, I solved my problem. Here is my code!
'Flag that indicates if there is a "frozen" scenario stored in the other variables
Private frozen_scenario As Boolean
'Range that marks the first cell of the frozen header
Private range_freeze_begin As Excel.Range
'Range that marks the the first cell not contained by the frozen header
Private range_freeze_end As Excel.Range
'Range that marks the the first visible cell (in the not fixed pane)
Private first_visible_cell_not_fixed As Excel.Range
'Unfreezes the panes, saving the current scenario
Private Sub unfreezeLines()
With Globals.ThisAddIn.Application.ActiveWindow
If .FreezePanes Then
Dim frozen_pane_limit_line As Integer
Dim frozen_pane_limit_column As Integer
frozen_pane_limit_line = .Panes(1).VisibleRange.Rows.Count + 1
frozen_pane_limit_column = .Panes(1).VisibleRange.Columns.Count + 1
If .Panes.Count = 2 Then
If .Panes(1).VisibleRange(1, 1).Row = .Panes(2).VisibleRange(1, 1).Row Then
frozen_pane_limit_line = 1
Else
frozen_pane_limit_column = 1
End If
Me.first_visible_cell_not_fixed = .Panes(2).VisibleRange(1, 1)
Else '4 panes
Me.first_visible_cell_not_fixed = .Panes(4).VisibleRange(1, 1)
End If
Me.range_freeze_begin = .Panes(1).VisibleRange(1, 1)
Me.range_freeze_end = Me.sheet.Cells(frozen_pane_limit_line, frozen_pane_limit_column)
Me.frozen_scenario = True
.FreezePanes = False
End If
End With
End Sub
'Recovers the frozen state, exactly like it was when the first function was called
Private Sub recuperaLinhasCongeladas()
If Me.frozen_scenario Then
'Creating the frozen header again
Globals.ThisAddIn.Application.Goto(Me.range_freeze_begin, True)
Me.range_freeze_end.Select()
Globals.ThisAddIn.Application.ActiveWindow.FreezePanes = True
'Showing the same cell at the top
Globals.ThisAddIn.Application.Goto(Me.first_visible_cell_not_fixed, True)
Me.frozen_scenario = False
End If
End Sub

Related

How to get the number of objects found in each layer of the active autocad drawing

Can any one explain me to get the object entites count of the layer
using vba code acad
I think You should use SelectionSets
Public Sub SelsetByLayer()
Dim ss As AcadSelectionSet
Dim FilterType(0) As Integer
Dim FilterData(0) As Variant
FilterType(0) = 8 ' DXF code of Layer property
For I = 0 To ThisDrawing.Layers.Count
' ThisDrawing.SelectionSets.Item(0).Delete
Set ss = ThisDrawing.SelectionSets.Add("test") ' You need to ensure if such selection set not exist yet .
FilterData(0) = ThisDrawing.Layers.Item(I).Name
ss.Select acSelectionSetAll, , , FilterType, FilterData
Next
End Sub
Further to the original answer, about using selection sets.
Here it is slightly modified:
Public Sub SelsetByLayer()
Dim ss As AcadSelectionSet
Dim FilterType(0) As Integer
Dim FilterData(0) As Variant
FilterType(0) = 8 ' DXF code of Layer property
For I = 0 To ThisDrawing.Layers.Count
Set ss = CreateSelectionSet("test")
FilterData(0) = ThisDrawing.Layers.Item(I).Name
ss.Select acSelectionSetAll, , , FilterType, FilterData
Next
End Sub
Public Function CreateSelectionSet(SelName As String) As AcadSelectionSet
On Error Resume Next
' Create a new selection set
' Delete any existing selection set with the specified name
With ThisDrawing
Set CreateSelectionSet = .SelectionSets.Add(SelName)
If (Err.Number <> 0) Then
Err.Clear
.SelectionSets.Item(SelName).Delete
Set CreateSelectionSet = .SelectionSets.Add(SelName)
End If
End With
End Function
I have added in the missing method for managing the deletion of existing selection set.
ss.Count will have the number of entities found. But please bear in mind that you may have layers frozen off etc. in the drawing and I think these will be excluded from the totals.

Determining if AutoShapes overlap/occlude in Excel and moving vertically to resolve

I am using some VBA code to create an autoshape and a text box, group them, and move to a vertical and horizontal position based on cell positions.
The code will look at user input to create and group the shape & textbox, and will usually create over 100 shapes, many of which will overlap. Currently, the groups are placed with reference to the top of a row; I want to separate them so that they don't overlap.
I would like to be able to determine if a group overlaps another group, and if so, to move it down 25pts. Given that this check would need to then determine if the new position also overlaps, it's becoming a bit too complicated for my skill level (self-taught beginner.)
I have researched this extensively, and I've come across the following VBA code:
Application.ScreenUpdating = False
Dim wb As Workbook
Set wb = ActiveWorkbook
Dim sh As Worksheet
Set sh = wb.ActiveSheet
Dim s1 As Shape
Dim s2 As Shape Dim CheckOverlap As Boolean
For i = 1 To 10 'sh.Shapes.Count
If i <= sh.Shapes.Count Then
Set s1 = sh.Shapes(i)
CheckOverlap = False
For Each s2 In Worksheets("Plan").Shapes
If s2.Left < (s1.Left + s1.Width) And s2.Top < (s1.Top + s1.Height) Then
CheckOverlap = True
Exit For
End If
Next
If CheckOverlap = True Then
s2.Top = s2.Top + 30
End If
End If
Next
End Sub
I found the basis of the code here:
Hit-Testing and Resolving Occlusion of AutoShapes in Excel
However, I haven't been able to figure it out how to make it check whether overlap occurs vertically as well as horizontally, as well as the multiple-overlap problem. Currently, if I execute that code, it just moves every shape down even irrespective of whether it overlaps.
If someone could help me out I would really appreciate it! This is the hardest part of my project and I'd love to find a solution.
Many thanks for your help
Try the below code. This should align all the charts on the active sheet vertically 25 points apart
Sub MoveShapes()
Dim IncrementTop, TopPosition, LeftPosition, i as Long
IncrementTop = 0
LeftPosition = 'place the desired starting left position here
TopPosition = 'place the desired starting top position here
For i = 1 To ActiveSheet.Shapes.Count
ActiveSheet.Shapes(i).Left = LeftPosition
ActiveSheet.Shapes(i).Top = TopPosition + IncrementTop
IncrementTop = IncrementTop + 25
Next i
End Sub
Found an answer:
Sub MoveShapes1()
Application.ScreenUpdating = False
Dim wb As Workbook
Set wb = ActiveWorkbook
Dim sh As Worksheet
Set sh = wb.ActiveSheet
Dim s1 As Shape
Dim s2 As Shape
Dim CheckOverlap As Boolean
For i = 1 To sh.Shapes.Count
If i <= sh.Shapes.Count Then
Set s1 = sh.Shapes(i)
Search:
CheckOverlap = False
For Each s2 In Worksheets("Plan").Shapes
If s2.ID = s1.ID Then GoTo Suit
If s2.Left <= (s1.Left + s1.Width) And s2.Left >= s1.Left _
And s2.Top <= (s1.Top + s1.Height) And s2.Top >= s1.Top Then
s1.Top = s1.Top + 32
CheckOverlap = True
Exit For
End If
Suit:
Next
If CheckOverlap = True Then GoTo Search
End If
Next
Application.ScreenUpdating = True
End Sub

Excel VBA Run Time Error '424' object required

I am totally new in VBA and coding in general, am trying to get data from cells from the same workbook (get framework path ...) and then to start application (QTP) and run tests.
I am getting this error when trying to get values entered in excel cells:
Run Time Error '424' object required
I believe I am missing some basic rules but I appreciate your help. Please see below the part of code in question:
Option Explicit
Private Sub RunTest_Click()
Dim envFrmwrkPath As Range
Dim ApplicationName As Range
Dim TestIterationName As Range
'Dim wb As Workbook
'Dim Batch1 As Worksheets
Dim objEnvVarXML, objfso, app As Object
Dim i, Msgarea
Set envFrmwrkPath = ActiveSheet.Range("D6").Value ' error displayed here
Set ApplicationName = ActiveSheet.Range("D4").Value
Set TestIterationName = ActiveSheet.Range("D8").Value
The first code line, Option Explicit means (in simple terms) that all of your variables have to be explicitly declared by Dim statements. They can be any type, including object, integer, string, or even a variant.
This line: Dim envFrmwrkPath As Range is declaring the variable envFrmwrkPath of type Range. This means that you can only set it to a range.
This line: Set envFrmwrkPath = ActiveSheet.Range("D6").Value is attempting to set the Range type variable to a specific Value that is in cell D6. This could be a integer or a string for example (depends on what you have in that cell) but it's not a range.
I'm assuming you want the value stored in a variable. Try something like this:
Dim MyVariableName As Integer
MyVariableName = ActiveSheet.Range("D6").Value
This assumes you have a number (like 5) in cell D6. Now your variable will have the value.
For simplicity sake of learning, you can remove or comment out the Option Explicit line and VBA will try to determine the type of variables at run time.
Try this to get through this part of your code
Dim envFrmwrkPath As String
Dim ApplicationName As String
Dim TestIterationName As String
Simply remove the .value from your code.
Set envFrmwrkPath = ActiveSheet.Range("D6").Value
instead of this, use:
Set envFrmwrkPath = ActiveSheet.Range("D6")
You have two options,
-If you want the value:
Dim MyValue as Variant ' or string/date/long/...
MyValue = ThisWorkbook.Sheets(1).Range("A1").Value
-if you want the cell object:
Dim oCell as Range ' or object (but then you'll miss out on intellisense), and both can also contain more than one cell.
Set oCell = ThisWorkbook.Sheets(1).Range("A1")
Private Sub CommandButton1_Click()
Workbooks("Textfile_Receiving").Sheets("menu").Range("g1").Value = PROV.Text
Workbooks("Textfile_Receiving").Sheets("menu").Range("g2").Value = MUN.Text
Workbooks("Textfile_Receiving").Sheets("menu").Range("g3").Value = CAT.Text
Workbooks("Textfile_Receiving").Sheets("menu").Range("g4").Value = Label5.Caption
Me.Hide
Run "filename"
End Sub
Private Sub MUN_Change()
Dim r As Integer
r = 2
While Range("m" & CStr(r)).Value <> ""
If Range("m" & CStr(r)).Value = MUN.Text Then
Label5.Caption = Range("n" & CStr(r)).Value
End If
r = r + 1
Wend
End Sub
Private Sub PROV_Change()
If PROV.Text = "LAGUNA" Then
MUN.Text = ""
MUN.RowSource = "Menu!M26:M56"
ElseIf PROV.Text = "CAVITE" Then
MUN.Text = ""
MUN.RowSource = "Menu!M2:M25"
ElseIf PROV.Text = "QUEZON" Then
MUN.Text = ""
MUN.RowSource = "Menu!M57:M97"
End If
End Sub

looping through worksheet command buttons and change visibility

I'm trying to write a code to make a number of buttons visible depending on a cell value
I have 10 command buttons all are invisible and I want to show only the first x
x is the value of cell "A1" in "Sheet1" (will be from 1 to 10)
Command buttons names are default names (CommandButton4, CommandButton5, ... , CommandButton13)
Note: I'm working with a worksheet not a userform
This is my code but i need something shorter and more pro and efficient
Private Sub CommandButton15_Click()
Dim i As Long
Dim CommandButton() As Variant
Application.ScreenUpdating = False
CommandButton = Array("CommandButton4", "CommandButton5", "CommandButton6", "CommandButton7", "CommandButton8", "CommandButton9", "CommandButton10", "CommandButton11", "CommandButton12", "CommandButton13")
For i = LBound(CommandButton) To LBound(CommandButton) + Sheet1.Range("A1").Value - 1
Sheet1.Shapes(CommandButton(i)).Visible = True
Next i
Application.ScreenUpdating = True
End Sub
Need ur help plz
As said in the comment you should rename your buttons. That just makes things easier.
You could for example name them "btn1", "btn2", "btn3" ....
Your code is ok and i can't see major errors. I don't know if you want to add new buttons later.
If so i would recommend something more generic. If you rename the buttons to "btn1"... then you could use something like this:
Private Sub CommandButton15_Click()
Dim btn As OLEObject, name As String, i As Long
i = Sheets(1).Range("A1").Value + 1
For Each btn In ActiveSheet.OLEObjects
name = btn.name
If btn.OLEType = xlButtonOnly And InStr(name, "btn") = 1 Then
If Int(Right(name, Len(name) - 3)) < i Then
btn.Visible = True
Else
btn.Visible = False
End If
End If
Next
End Sub
So you can add new buttons name them with the "btn.." pattern and you don't have to change your Code.

Excel 2010: how to use autocomplete in validation list

I'm using a large validation list on which a couple of vlookup() functions depend. This list is getting larger and larger. Is there a way to type the first letters of the list item I'm looking for, instead of manually scrolling down the list searching for the item?
I've done some Googling but this suggests that this is indeed possible in earlier versions of Excel, but not in Excel 2010. Hope you guys can help.
Here is a very good way to handle this (found on ozgrid):
Let's say your list is on Sheet2 and you wish to use the Validation List with AutoComplete on Sheet1.
On Sheet1 A1 Enter =Sheet2!A1 and copy down including as many spare rows as needed (say 300 rows total). Hide these rows and use this formula in the Refers to: for a dynamic named range called MyList:
=OFFSET(Sheet1!$A$1,0,0,MATCH("*",Sheet1!$A$1:$A$300,-1),1)
Now in the cell immediately below the last hidden row use Data Validation and for the List Source use =MyList
[EDIT] Adapted version for Excel 2007+ (couldn't test on 2010 though but AFAIK, there is nothing really specific to a version).
Let's say your data source is on Sheet2!A1:A300 and let's assume your validation list (aka autocomplete) is on cell Sheet1!A1.
Create a dynamic named range MyList that will depend on the value of the cell where you put the validation
=OFFSET(Sheet2!$A$1,MATCH(Sheet1!$A$1&"*",Sheet2!$A$1:$A$300,0)-1,0,COUNTA(Sheet2!$A:$A))
Add the validation list on cell Sheet1!A1 that will refert to the list =MyList
Caveats
This is not a real autocomplete as you have to type first and then click on the validation arrow : the list will then begin at the first matching element of your list
The list will go till the end of your data. If you want to be more precise (keep in the list only the matching elements), you can change the COUNTA with a SUMLPRODUCT that will calculate the number of matching elements
Your source list must be sorted
Here's another option. It works by putting an ActiveX ComboBox on top of the cell with validation enabled, and then providing autocomplete in the ComboBox instead.
Option Explicit
' Autocomplete - replacing validation lists with ActiveX ComboBox
'
' Usage:
' 1. Copy this code into a module named m_autocomplete
' 2. Go to Tools / References and make sure "Microsoft Forms 2.0 Object Library" is checked
' 3. Copy and paste the following code to the worksheet where you want autocomplete
' ------------------------------------------------------------------------------------------------------
' - autocomplete
' Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' m_autocomplete.SelectionChangeHandler Target
' End Sub
' Private Sub AutoComplete_Combo_KeyDown(ByVal KeyCode As msforms.ReturnInteger, ByVal Shift As Integer)
' m_autocomplete.KeyDownHandler KeyCode, Shift
' End Sub
' Private Sub AutoComplete_Combo_Click()
' m_autocomplete.AutoComplete_Combo_Click
' End Sub
' ------------------------------------------------------------------------------------------------------
' When the combobox is clicked, it should dropdown (expand)
Public Sub AutoComplete_Combo_Click()
Dim ws As Worksheet: Set ws = ActiveSheet
Dim cbo As OLEObject: Set cbo = GetComboBoxObject(ws)
Dim cb As ComboBox: Set cb = cbo.Object
If cbo.Visible Then cb.DropDown
End Sub
' Make it easier to navigate between cells
Public Sub KeyDownHandler(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Const UP As Integer = -1
Const DOWN As Integer = 1
Const K_TAB_______ As Integer = 9
Const K_ENTER_____ As Integer = 13
Const K_ARROW_UP__ As Integer = 38
Const K_ARROW_DOWN As Integer = 40
Dim direction As Integer: direction = 0
If Shift = 0 And KeyCode = K_TAB_______ Then direction = DOWN
If Shift = 0 And KeyCode = K_ENTER_____ Then direction = DOWN
If Shift = 1 And KeyCode = K_TAB_______ Then direction = UP
If Shift = 1 And KeyCode = K_ENTER_____ Then direction = UP
If Shift = 1 And KeyCode = K_ARROW_UP__ Then direction = UP
If Shift = 1 And KeyCode = K_ARROW_DOWN Then direction = DOWN
If direction <> 0 Then ActiveCell.Offset(direction, 0).Activate
AutoComplete_Combo_Click
End Sub
Public Sub SelectionChangeHandler(ByVal Target As Range)
On Error GoTo errHandler
Dim ws As Worksheet: Set ws = ActiveSheet
Dim cbo As OLEObject: Set cbo = GetComboBoxObject(ws)
Dim cb As ComboBox: Set cb = cbo.Object
' Try to hide the ComboBox. This might be buggy...
If cbo.Visible Then
cbo.Left = 10
cbo.Top = 10
cbo.ListFillRange = ""
cbo.LinkedCell = ""
cbo.Visible = False
Application.ScreenUpdating = True
ActiveSheet.Calculate
ActiveWindow.SmallScroll
Application.WindowState = Application.WindowState
DoEvents
End If
If Not HasValidationList(Target) Then GoTo ex
Application.EnableEvents = False
' TODO: the code below is a little fragile
Dim lfr As String
lfr = Mid(Target.Validation.Formula1, 2)
lfr = Replace(lfr, "INDIREKTE", "") ' norwegian
lfr = Replace(lfr, "INDIRECT", "") ' english
lfr = Replace(lfr, """", "")
lfr = Application.Range(lfr).Address(External:=True)
cbo.ListFillRange = lfr
cbo.Visible = True
cbo.Left = Target.Left
cbo.Top = Target.Top
cbo.Height = Target.Height + 5
cbo.Width = Target.Width + 15
cbo.LinkedCell = Target.Address(External:=True)
cbo.Activate
cb.SelStart = 0
cb.SelLength = cb.TextLength
cb.DropDown
GoTo ex
errHandler:
Debug.Print "Error"
Debug.Print Err.Number
Debug.Print Err.Description
ex:
Application.EnableEvents = True
End Sub
' Does the cell have a validation list?
Function HasValidationList(Cell As Range) As Boolean
HasValidationList = False
On Error GoTo ex
If Cell.Validation.Type = xlValidateList Then HasValidationList = True
ex:
End Function
' Retrieve or create the ComboBox
Function GetComboBoxObject(ws As Worksheet) As OLEObject
Dim cbo As OLEObject
On Error Resume Next
Set cbo = ws.OLEObjects("AutoComplete_Combo")
On Error GoTo 0
If cbo Is Nothing Then
'Dim EnableSelection As Integer: EnableSelection = ws.EnableSelection
Dim ProtectContents As Boolean: ProtectContents = ws.ProtectContents
Debug.Print "Lager AutoComplete_Combo"
If ProtectContents Then ws.Unprotect
Set cbo = ws.OLEObjects.Add(ClassType:="Forms.ComboBox.1", Link:=False, DisplayAsIcon:=False, _
Left:=50, Top:=18.75, Width:=129, Height:=18.75)
cbo.name = "AutoComplete_Combo"
cbo.Object.MatchRequired = True
cbo.Object.ListRows = 12
If ProtectContents Then ws.Protect
End If
Set GetComboBoxObject = cbo
End Function
Building on the answer of JMax, use this formula for the dynamic named range to make the solution work for multiple rows:
=OFFSET(Sheet2!$A$1,MATCH(INDIRECT("Sheet1!"&ADDRESS(ROW(),COLUMN(),4))&"*",Sheet2!$A$1:$A$300,0)-1,0,COUNTA(Sheet2!$A:$A))
Excel automatically does this whenever you have a vertical column of items. If you select the blank cell below (or above) the column and start typing, it does autocomplete based on everything in the column.
As other people suggested, you need to use a combobox. However, most tutorials show you how to set up just one combobox and the process is quite tedious.
As I faced this problem before when entering a large amount of data from a list, I can suggest you use this autocomplete add-in . It helps you create the combobox on any cells you select and you can define a list to appear in the dropdown.
=OFFSET(NameList!$A$2:$A$200,MATCH(INDIRECT("FillData!"&ADDRESS(ROW(),COLUMN(),4))&"*",NameList!$A$2:$A$200,0)-1,0,COUNTIF($A$2:$A$200,INDIRECT("FillData!"&ADDRESS(ROW(),COLUMN(),4))&"*"),1)
Create sheet name as Namelist. In column A fill list of data.
Create another sheet name as FillData for making data validation list as you want.
Type first alphabet and select, drop down menu will appear depend on you type.