Можете ли вы прервать код VBA, чтобы сделать выбор листа? - PullRequest
0 голосов
/ 27 сентября 2018

Я постараюсь быть максимально понятным в описании, поэтому здесь ничего не говорится:

Я создал код, в котором пользователь выбирает свой файл Excel, а затем макроскопирует Sheet из этого файла в мой макрос Workbook.

MyFile = Application.GetOpenFilename()
    Workbooks.Open (MyFile)
        ActiveSheet.Copy After:=wbook.Sheets(1)
        ActiveSheet.Name = "Selected file"
    Workbooks.Open (MyFile)
ActiveWorkbook.Close SaveChanges:=False

Это работает, но я понял, что могут быть случаи, когда выбранный файл имеет несколько Sheets.

Есть ли способ написать макрос, в котором, если у моего выбранного файла есть 1 лист, он выполняет приведенный выше код, и если у него есть более одного листа, чтобы я мог выбрать лист, который я хочу, а затем запустить остальную частькод

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

В целом, я бы порекомендовал решение ashleedawg, но если бы вы настаивали на сохранении структуры кода, ваш код мог бы выглядеть примерно так:

Вы можете различать количество листовРабочая книга использует свойство .Count объекта Sheets (или Worksheets, если вы не хотите включать Chart s) и используйте InputBox для проверки нужного листа.ищите.

MyFile = Application.GetOpenFilename()
Workbooks.Open (MyFile)

If ThisWorkbook.Sheets.Count = 1 Then
  ThisWorkbook.ActiveSheet.Copy After:=wbook.Sheets(1)
  ThisWorkbook.ActiveSheet.Name = "Selected File"
Else
  Dim checkfor As String
  checkfor = InputBox("What Sheet should I execute the code for?")

  Dim i As Integer
  For i = 0 To ThisWorkbook.Sheets.Count
     If Trim(LCase(checkfor)) = Trim(LCase(Sheets(i).Name))) Then
        ThisWorkbook.Sheets(i).Copy After := wbook.Sheets(1)
        ThisWorkbook.Sheets(i).Name = "Selected file"
     End If
  Next i
End If

Workbooks.Open (MyFile)
ActiveWorkbook.Close SaveChanges:=False

Может потребоваться дальнейшая настройка, потому что я не был уверен, чего именно вы хотели достичь.

0 голосов
/ 27 сентября 2018

Редактировать:

  • Я подумал о другом способе справиться с этим - возможно, ближе к тому, что вы искали.,,

    img

Это просто расширение базовой паузы , которую яиспользовать время от времени.

Это моя "обычная" Pause процедура (с использованием функции Timer ):

Sub Pause(seconds As Single)
    Dim startTime As Single
    startTime = Timer                          'get current timer count
    Do
        DoEvents                               'let Windows "catch up"
    Loop Until Timer > startTime + seconds     'repeat until time's up
End Sub

... такДала мне идею.

Честно говоря, я был немного удивлен, обнаружив, что это работает, поскольку он в основном выполняет две секции кода одновременно .


Код для WaitForUserActivity:

Вот код, который я использовал в приведенной выше демонстрации:

Option Explicit
Public isPaused As Boolean

Sub WaitForUserActivity()                   'THE 'RUN DEMO' BUTTON runs this sub.

    Dim origSheet As String
    isPaused = True                                   'flag "pause mode" as "on"
    origSheet = ActiveSheet.Name                'remember current worksheet name

    MsgBox "This will 'pause' code execution until you" & vbLf & _
           "click the 'Continue' button, or select a different a worksheet."
    Application.StatusBar = "PAUSED: Click ""Continue"", or select a worksheet."

    Do                                       'wait for button click or ws change
        DoEvents        'yield execution so that the OS can process other events
    Loop Until (Not isPaused) Or (ActiveSheet.Name <> origSheet)

    If isPaused Then                           'the active worksheet was changed
        MsgBox "Worksheet '" & ActiveSheet.Name & "' was selected." _
              & vbLf & vbLf & "Now the program can continue..."
    Else                                                 'the button was clicked
        MsgBox "The 'Continue' button was clicked." _
              & vbLf & vbLf & "Now the program can continue..."
    End If
    Application.StatusBar = "Ready"
End Sub

Sub btnContinue()                          'THE 'CONTINUE' BUTTON runs this sub.
    isPaused = False                                 'flag "pause mode" as "off"
End Sub

Для запуска демонстрации :

  • поместите вышеуказанный код вобычный модуль
  • убедитесь, что в книге есть как минимум две таблицы
  • , создайте две кнопки управления:
    • одну для кнопки " Run Demo ",назначьте макрос: WaitForUserActivity
    • один для кнопки " Продолжить ", назначьте макрос: btnContinue
  • нажмите "Кнопка запуска демонстрации"

Ключевой командой в коде является DoEvents Функция , которая" приводит к выполнению, так что операционная система может обрабатывать другиесобытия. "

DoEvents передает управление операционной системе.Управление возвращается после того, как операционная система завершила обработку событий в своей очереди и все ключи в очереди SendKeys были отправлены.

DoEvents наиболее полезен для простых вещей, таких как разрешение пользователю отменить процесс после его запуска, например, поиск файла.Для длительных процессов выход из процессора лучше выполнить с помощью таймера или делегирования задачи компоненту ActiveX EXE, а операционная система позаботится о многозадачности и сокращении времени.

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

Дополнительные сведения (и предупреждения) в источнике .



Оригинальный ответ:

Некоторые предлагаемые решения:

  1. Вместо "остановки" кода вы можете предложить пользователю указать, какой лист.

    • Самый простой способ - использовать InputBox, где пользователь вводит идентификационный номер или иным образом идентифицирует рабочий лист.

    • Более сложный, но более надежныйи профессионально выглядящий будет настраиваемое диалоговое окно с помощью пользовательской формы.В Интернете есть несколько примеров и учебных пособий, таких как этот .

  2. Вы можете "приостановить" выполнение , чтобы датьпользователь устанавливает количество времени для выбора листа с помощью простого цикла таймера , и вы даже можете проверить имя листа, чтобы увидеть, выбрал ли пользователь новый, что-то вроде этого:

    Dim startTime As Single, shtName As String
    If ThisWorkbook.Worksheets.Count = 1 Then
        MsgBox "There is only one worksheet in this workbook."
    Else
        shtName = ActiveSheet.Name 'get name of active sheet
        MsgBox "You have 5 seconds to select a worksheet after clicking OK.", _
            vbOKOnly + vbInformation, "Select a worksheet... fast!"
        startTime = Timer
        Do
            DoEvents
        Loop Until Timer > startTime + 5
    
        'check if user picked a new worksheet
        If ActiveSheet.Name = shtName Then
            MsgBox "You didn't select a new worksheet!"
        Else
            MsgBox "Thanks for selecting a new worksheet!"
        End If
    End If
    

    Это немного глупо, но может сработать, особенно если правильно проверить, чтобы убедиться, что вы получили правильный лист сейчас.

  3. Полагаю, вы могли бы создать процедура события рабочего листа , которая запускается при активации рабочего листа, и проверяет глобальную переменную, чтобы проверить, была ли запущена ваша "процедура импорта" , и если да, возобновить ваш код... но это было бы грязно и запутанно и потребовало бы наличия кода в рабочей книге, которую вы "импортируете".

  4. или лучше, чем любой из этих будет программно / логически определять, какая работалист вам нужно в зависимости от содержимого листа.Есть ли название?Определенная дата?Может быть, самый новый лист?Что-то в определенной клетке?Должно быть что-то, что отличает это от других.

Надеюсь, это даст вам некоторые идеи для нелинейного решения.?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...