2015-07-08 1 views
2

Я провел большую часть последних нескольких недель, пытаясь создать несколько пользовательских форм (не из моих сильных сторон). С моей предполагаемой пользовательской формой пользователь может выбрать любые значения, которые они хотят в электронной таблице (например, цены активов), а затем применить счетчик, это подражает увеличению/уменьшению% в цене этих активов и т. Д., А затем они могут наблюдать, как это влияет на различные аспекты бизнеса. Затем у них есть две кнопки, одна из которых позволяет сохранить настроенные значения, а другая - для сброса значений.Изменить пользовательскую форму для работы на нескольких листах

До сих пор у меня есть одна пользовательская форма, которая, как представляется, работает на разных листах, но выбранные диапазоны должны быть смежными, и один, с большой помощью здесь (см. Предыдущий вопрос от меня самого), который отлично работает для несмежных выборов, однако они должны быть на одном листе. Однако в идеале я хотел бы иметь возможность выбирать несколько несмежных диапазонов по нескольким листам и иметь возможность редактировать их. Я уверенно информирован о том, что переменные диапазона могут относиться только к диапазонам на конкретном листе, который, я полагаю, является местом, где я ошибаюсь.

Код, который работает для несмежных диапазонов, ниже, я, честно говоря, не могу воспользоваться большим успехом для достижения этой цели, хотя мне нужна была большая помощь отсюда, и я полностью не прибрал его полностью , может ли кто-нибудь предложить, как я мог бы отредактировать или обновить это, чтобы одновременно работать с многочисленными листами и несмежными диапазонами?

Открытие Userform;

Public myRange As Range, myArea As Range 
Public myCopy As Variant 
Public i As Long, numAreas As Long 
Public pvar As Double 

Sub Button2_Click() 
Spinner.Show 
End Sub 

пользовательской формы:

Option Explicit 

'on opening userform this sets the variables 

Private Sub UserForm_Activate() 

pvar = 1 

Set myRange = Selection 

    numAreas = myRange.Areas.Count 
    If numAreas = 1 Then 
     myCopy = myRange.Value 
    Else 
     ReDim myCopy(1 To numAreas) 
     For i = 1 To numAreas 
      myCopy(i) = myRange.Areas(i).Value 
     Next i 
    End If 
End Sub 

'Useful Subs 

Sub RestoreVals(R As Range, V As Variant) 
    Dim A As Range 
    Dim i As Long, n As Long 
    n = R.Areas.Count 
    If n = 1 Then 
     R.Value = V 
    Else 
     For i = 1 To n 
      R.Areas(i).Value = V(i) 
     Next i 
    End If 
End Sub 

Sub Multiply(R As Range, p As Double) 
    Dim c As Range 
    For Each c In R.Cells 
     c.Value = p * c.Value 
    Next c 
End Sub 

'Spin Up button 

Private Sub SpinButton1_SpinUp() 

Dim myRange As Range, myCopy As Variant 

    Set myRange = Selection 

'Reset Values so that pvar is * by the right values 

    CopyVals myRange, myCopy 
    Multiply myRange, (1/pvar) 

'Now * by pvar 

    CopyVals myRange, myCopy 
    pvar = pvar + UpBox.Value/100 
    Multiply myRange, pvar 

End Sub 

' Spin Down button 

Private Sub SpinButton1_SpinDown() 

Dim myRange As Range, myCopy As Variant 

    Set myRange = Selection 

'Reset Values so that pvar is * by the right values 

    CopyVals myRange, myCopy 
    Multiply myRange, (1/pvar) 

'Now * by pvar 

    CopyVals myRange, myCopy 
    pvar = pvar - DownBox.Value/100 
    Multiply myRange, pvar 

End Sub 

'Button to return to starting values 

Public Sub DefaultButton_Click() 

If numAreas = 1 Then 
     myRange.Value = myCopy 
    Else 
     For i = 1 To numAreas 
      myRange.Areas(i).Value = myCopy(i) 
     Next i 
    End If 

End Sub 

'button to maintain adjusted values 

Private Sub CommandButton1_Click() 

UserForm3.Show 

End Sub 
+0

Для хранения отдельных диапазонов вам понадобится «Коллекция» (или словарь или массив), чтобы вы могли прокручивать их, когда это необходимо. Как вы заявляете в своем сообщении, переменная «Range» может ссылаться только на диапазоны на одном листе. – Rory

+0

Другие (возможные) подходы могут заключаться в том, чтобы скопировать ваши выборки на новый временный листок и работать с ними там, или просто поставить очередь листов и выполнять вычисления на одном листе за раз. – Lumigraphics

ответ

2

В качестве доказательства концепции я создал следующую пользовательскую форму. В редакторе я устанавливаю ShowModal равным False. Это важно, поскольку позволяет пользователю переключаться на разные листы, пока отображается форма. Это выглядит следующим образом:

enter image description here

Следующий код показывает один способ, позволяющий пользователю выбрать, возможно несмежные диапазоны на отдельных листах, изменять их с помощью множителя, а затем восстановить исходные значения:

Option Explicit 
Dim valCopies As Collection 
Dim ranges As Collection 

Private Sub UserForm_Initialize() 
    Dim r As Range 
    tbChangeFactor.Value = "1.0" 
    Set ranges = New Collection 
    Set valCopies = New Collection 
    For Each r In Selection.Areas 
     ranges.Add r 
     valCopies.Add r.Value 
    Next r 
End Sub 

Private Sub btnChange_Click() 
    Dim r As Range, c As Range, p As Double 

    Application.ScreenUpdating = False 
    p = tbChangeFactor.Value 
    For Each r In ranges 
     For Each c In r.Cells 
      c = c * p 
     Next c 
    Next r 
    Application.ScreenUpdating = True 
End Sub 

Private Sub btnRestore_Click() 
    Dim i As Long, n As Long 

    n = ranges.Count 
    For i = 1 To n 
     ranges(i).Value = valCopies(i) 
    Next i 
End Sub 

Private Sub btnSelect_Click() 
    Dim choice As Range, A As Range 
    Dim home As Worksheet, ws As Worksheet 

    Set valCopies = New Collection 
    Set ranges = New Collection 
    Set home = ActiveSheet 
    For Each ws In Sheets 
     ws.Select 
     Set choice = Nothing 
     On Error Resume Next 'when the user hits cancel 
     Set choice = Application.InputBox("Select cells from " & ws.Name, "Change/Restore", Selection.Address, , , , , 8) 
     On Error GoTo 0 
     If Not choice Is Nothing Then 
      choice.Select 'for future reference 
      For Each A In choice.Areas 
       ranges.Add A 
       valCopies.Add A.Value 
      Next A 
     End If 
    Next ws 
    home.Select 
End Sub  

Было бы легко модифицировать так, чтобы диапазон выбора выбора выполнялся только по заданному набору листов. Если я понимаю, что вы пытаетесь сделать, возможно, вы захотите запустить вспомогательный модуль восстановления в начале субстрата выбора, если вы хотите убедиться, что исходные (в отличие от измененных) значения сохраняются, когда пользователь запускает выбор не более одного раза. Код не был тщательно протестирован, но, похоже, работает. Слово предупреждения - области могут перекрываться, если пользователь делает странные вещи при выборе. Вышеприведенный код модифицирует любые ячейки, содержащиеся в таких перекрытиях 2 (или более) раза. Чтобы быть действительно безопасным, вы можете изменить код выбора, чтобы убедиться, что области не перекрываются.Один из способов заключается в том, чтобы управлять областями с помощью превосходной функции OwnUnion Чипа Пирсона: http://www.cpearson.com/Excel/BetterUnion.aspx

+0

Спасибо за вашу помощь снова Джон. Когда я получу шанс, я пойду на реализацию этой методологии. – Sam

+0

Привет, Джон. Это блестяще, спасибо за вашу помощь. Извините, на это потребовалось так много времени, чтобы ответить, это немного заняло заднее сиденье. – Sam

0

Каждый Excel Window отслеживает клетки выбраны, чтобы вы могли цикл через Windows коллекции:

Dim wdw As Window 
For Each wdw In Application.Windows 
     Debug.Print wdw.Selection.Address(External:=True) 
Next wdw 

Но проблема с этим подходом является что ваш код должен убедиться, что пользователь только открыл ожидаемые книги или проверил каждую книгу. Кроме того, что происходит, если пользователь имеет книгу в нескольких представлениях (кнопка «Новое окно» на вкладке «Вид»)?

Смежные вопросы