2014-01-08 2 views
0

У меня есть «лист 1» с необработанными данными. Количество строк и столбцов всегда отличается. Колонки показывают температуру, изменяющую функцию времени. Как показано:Максимальное значение каждого столбца из динамического диапазона

ColumnA (время) 0.000/Столбец B (TC1) 27.342/Столбец C (TC2) 26.409/Столбец D (TC3) ... и т. Д.

Я хотел бы найти максимальное значение в каждом столбце температуры и скопировать и вставить их транспонирование на «sheet2», склеивание и его первый ряд, и соответствующий пиковую температуру с ее строкой, как это показано ниже:

TC1 305.387 (максимальное значение) 354 (строка)/TC2 409.989 (максимальное значение) 575 (строка)/TC3 789.383 (максимальный темп) 899 (строка) ... и т. Д.

Дело в том, что я использую свой собственный диапазон ... каждый раз, когда я использую код, я выбираю другой диапазон, иногда включает в себя все строки и некоторые столбцы, иногда несколько строк и все столбцы и т. Д. Ниже это MyRange код:

Public Sub run_CalcPeakTemp() 
Dim myCalRange As Range 
Dim iReply As Integer 
On Error Resume Next 
Set myCalcRange = Application.InputBox(Prompt:="Select first row and then Ctrl+Shift+down", Title:="Select Range", Type:=8) 
myCalcRange.Select 
If myCalcRange Is Nothing Then 
iReply = MsgBox("Range not selected!") 
Exit Sub 
If myCalcRange Is notNothing Then 
Call run_CalcPeakTemp 
End If 
End If 

А вот где я застрял ... Я не в состоянии сделать это в цикле. Я сделал плохо слишком основной, как этот ... шаг за шагом ... Я новичок :(

Dim VarMaxVal As Variant 
VarMaxVal = 0 
VarMaxVal = Application.WorksheetFunction.Max(Columns(1)) 
Sheets("Calc").Select 
Range("A1").Select 
ActiveCell.Offset(1, 2).Range("A1").Select 
ActiveCell.FormulaR1C1 = VarMaxVal 

И так на остальной части колонны.

..... Пустоты Я смог скопировать первую строку моего динамического диапазона.

ответ

0

Это не ответ «сделай это, и все будет хорошо», потому что я не совсем понимаю, что ты пытаешься. Однако я надеюсь, что этот ответ включает достаточно указателей для создания кода, который вы ищете.

e 1

Вы абсолютно правильно используете функцию рабочего листа, а не свой собственный VBA, когда существует подходящая функция рабочего листа, поскольку функция рабочего листа будет значительно быстрее. Однако, если есть способ заставить функцию Max возвращать строку, я не знаю ее. Я считаю, что вам придется использовать VBA для сканирования каждого столбца.

Выпуск 2

On Error Resume Next никогда не должны использоваться, как это, так как все ошибки будут игнорироваться. В идеале вы избегаете ошибок, проверяя заранее. Если вы хотите открыть файл, вы должны проверить его существо, прежде чем пытаться открыть, а не ждать, пока open завершится с ошибкой, и сообщите об ошибке. Однако есть ситуации, когда вы не можете проверить наличие ошибки. В таких ситуациях вы можете использовать On Error Resume Next так:

Err.Clear 
    On Error Resume Next 
    ' Statement that might fail 
    On Error GoTo 0 
    If Err.Number <> 0 Then 
    ' Statement failed. 
    ' Description of failure in Err.Description. 
    ' Report error with user friendly message and exit or take corrective action. 
    End If 

Выпуск 3

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

1 Public Sub run_CalcPeakTemp() 
2 Dim myCalRange As Range 
3 Dim iReply As Integer 
4 'On Error Resume Next 
5 Set myCalcRange = Application.InputBox(Prompt:="Select first row and then Ctrl+Shift+down", _ 
6     Title:="Select Range", Type:=8) 
7 myCalcRange.Select 
8 If myCalcRange Is Nothing Then 
9  iReply = MsgBox("Range not selected!") 
10  Exit Sub 
11  If myCalcRange Is notNothing Then 
12  Call run_CalcPeakTemp 
13  End If 
14 End If 
15 End Sub 

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

Выпуск 4

В строке 2, вы объявляете myCalRange. В другом месте в рутине вы используете myCalcRange. Если первый оператор вашего модуля равен Option Explicit, во время компиляции вам будет сообщено, что myCalcRange не был объявлен. Если вы опустите Option Explicit, первая ссылка на myCalcRange будет выполнять неявное объявление. Обнаружение неявных деклараций может быть очень сложным. Всегда включайте Option Explicit.

Выпуск 5

линия 11 должна быть If Not myCalcRange Is Nothing Then. У VBA нет оператора IsNot, и место было не в том месте.

Выпуск 6

Я никогда не использовал InputBox таким образом, и я найти помощь в заблуждение:

  • Set MyRange = Application.InputBox (подсказка: = "Sample", введите: = 8)

  • Если вы не используете инструкцию Set, переменная устанавливается на значение в диапазоне, а не на объект Range.

Если myRange объявлен как Range то Set является обязательным. Если myRange объявлен как Variant, то Set запрещен. Если myRange не объявлен, и вы полагаетесь на неявное объявление, то myRange будет объявлен как Range, если вы включите Set и Variant, если вы его опустите.

Это не ваша ошибка. Эта функция (?) VBA составляет не менее 11 лет, и я могу только предположить, что кто-то думал, что они полезны.

Выпуск 7

7 myCalcRange.Select 
8 If myCalcRange Is Nothing Then 

Вы не можете выбрать диапазон, нет ничего. Тест должен быть первым.

Выпуск 8

8 If myCalcRange Is Nothing Then 
9  iReply = MsgBox("Range not selected!") 
10  Exit Sub 
11  If myCalcRange Is notNothing Then 
12  Call run_CalcPeakTemp 
13  End If 
14 End If 

С отступом вы можете увидеть, что весь этот код находится в пределах первого If. Я не уверен, что это то, что вы хотели. Ты имел ввиду?

8 If myCalcRange Is Nothing Then 
9  iReply = MsgBox("Range not selected!") 
10  Exit Sub 
14 End If 
11 If myCalcRange Is notNothing Then 
12  Call run_CalcPeakTemp 
13 End If 

Я предполагаю, что вы пытаетесь заставить пользователя выбрать диапазон. В общем, вы должны разрешить пользователю отменить выбор.В теории, чтобы заставить пользователя сделать выбор вам нужно что-то вроде:

Set myCalcRange = Nothing 
    Do While myCalcRange Is Nothing 
     Set myCalcRange = Application.InputBox ... 
    Loop   

На практике InputBox не позволяют пользователю нажать OK, если не был выбран и нажав Отменить дает ряд Ошибка VBA. InputBox(... type := 8) - это не утверждение, которое я когда-либо использовал!

Выпуск 9

12  Call run_CalcPeakTemp 

Рутинные называющие себя называются рекурсия и разрешен VBA, но он не может быть использован таким образом. Одним из возможных вариантов использования является поиск иерархии и получение значения внизу. Процедура проверяет наличие в нижней части иерархии. Если это так, он возвращает значение. Если это не так, он называет себя следующим уровнем вниз как его параметр.

Это VBA эквивалент простого использования рекурсии меня учили много лет назад:

Function Factorial(ByVal N As Long) As Long 
    If N = 1 Then 
    Factorial = 1 
    Else 
    Factorial = N * Factorial(N - 1) 
    End If 
End Function 

Эта процедура:

Sub Test() 
    Debug.Print "Factorial(1) = " & Factorial(1) 
    Debug.Print "Factorial(2) = " & Factorial(2) 
    Debug.Print "Factorial(3) = " & Factorial(3) 
    Debug.Print "Factorial(4) = " & Factorial(4) 
    Debug.Print "Factorial(5) = " & Factorial(5) 
End Sub 

отображает следующие в немедленном окне:

Factorial(1) = 1 
Factorial(2) = 2 
Factorial(3) = 6 
Factorial(4) = 24 
Factorial(5) = 120 

Некоторый код, который может быть полезен

Этот код соответствует моему предположению о вашем требовании.

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

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

Я думаю, что обучение программированию - это как научиться управлять автомобилем. В конце вашего первого урока вы знаете, что никогда не сможете работать с тремя педалями, шестерней, колесом и индикатором, проверяя зеркало. Но через месяц вы не можете вспомнить, почему вы нашли это настолько сложным. Добро пожаловать в радости программирования. Надеюсь, вы найдете это так же весело, как и я.

Sub ExtractMaxTemperatures() 

    ' I understand your temperatures are in columns 2 to 5. If I use these values 
    ' in the code and they change (perhaps because new columns are added) then you 
    ' will have to search the code for the appropriate 2s and 5s and replace them. 
    ' Constants allow me to use names which makes the code easier to understand. 
    ' Also if the column numbers change, change the constants and the code is fixed. 

    ' I have used Sheet1 to hold the full set of temperatures and Sheet2 to hold the 
    ' extracted maximums. In these constants, and in the variables below, replacing 
    ' "Sht1" and "Sht2" with something more meaningful will help make the code more 
    ' readable. 
    Const ColSht1TempFirst As Long = 2 
    Const ColSht1TempLast As Long = 5 
    Const RowSht1DataFirst As Long = 3 
    Const ColSht2Dest As Long = 2 
    Const RowSht2Dest As Long = 3 

    Dim ColSht1Crnt As Long 
    Dim RowSht1Crnt As Long 
    Dim ColSht2Crnt As Long 
    Dim RowSht2Crnt As Long 

    ' Declare fixed size arrays to hold the maximum temperature 
    ' and its row for each column 
    Dim TempMaxByCol(ColSht1TempFirst To ColSht1TempLast) As Single 
    Dim RowForMaxTemp(ColSht1TempFirst To ColSht1TempLast) As Long 

    Dim TempCrnt As Single 
    Dim TempMaxCrnt As Single 
    Dim RowForMaxCrnt As Long 

    Dim ShtValue As Variant 

    ' It is possible to check the values within the worksheet with statements 
    ' such as "If .Cells(RowCrnt, ColCrnt).Value = 5 Then" 
    ' However, it is much quicker to copy all values from the worksheet to an 
    ' array and process the values from the array. I have done this since I 
    ' will have to use arrays within the column loop. 

    ' I do not know the name of the worksheet containing the temperatue so I have 
    ' used Sheet1. 

    ' The statement "ShtValues = .UsedRange.Value" converts ShtValues to a two 
    ' dimensional array containing every value in in the worksheet. The rows 
    ' are dimension 1 and the columns are dimension 2 which is not the usual 
    ' arrangement. However, it means "ShtValue(RowCrnt, ColCrnt)" matches 
    ' ".Cells(RowCrnt, ColCrnt).Value" which avoids confusion. 

    ' Because I have loaded the entire worksheet, row and column numbers within 
    ' the array will match those in the worksheet. 

    With Worksheets("Sheet1") 
    ShtValue = .UsedRange.Value 
    End With 

    ' Loop for each temperature column 
    For ColSht1Crnt = ColSht1TempFirst To ColSht1TempLast 

    ' Your code assume no blank or non-numeric values within the temperature 
    ' ranges. However, were they to exist, the code would fail so I check. 

    RowForMaxCrnt = 0   ' Indicates no temperature saved yet 

     ' Loop for each data row column. UBound(ShtValue, 2) identifies the last row. 
     For RowSht1Crnt = RowSht1DataFirst To UBound(ShtValue, 1) 
     If IsNumeric(ShtValue(RowSht1Crnt, ColSht1Crnt)) Then 
      ' This cell is numeric 
      TempCrnt = Val(ShtValue(RowSht1Crnt, ColSht1Crnt)) 
      If RowForMaxCrnt <> 0 Then 
      ' A possible maximum temperature has already been stored. 
      ' Check current value against it. 
      If TempMaxCrnt < TempCrnt Then 
       ' Higher temperature found. Store details in temporary variables 
       RowForMaxCrnt = RowSht1Crnt 
       TempMaxCrnt = TempCrnt 
      End If 
      Else 
      ' First temperature found. Store details in temporary variables 
      RowForMaxCrnt = RowSht1Crnt 
      TempMaxCrnt = TempCrnt 
      End If 
     End If 
     Next 
     'Store values in temporary variable in arrays 
     TempMaxByCol(ColSht1Crnt) = TempMaxCrnt 
     RowForMaxTemp(ColSht1Crnt) = RowForMaxCrnt 

    Next 

    ' Initialise the current row to the start row of the outout table 
    RowSht2Crnt = RowSht2Dest 

    ' I think you call the destination sheet "Calc" but I have used "Sheet2" 

    With Worksheets("Sheet2") 

    ' Create header lines 
    ' TC1  TC2  TC3  TC4 
    ' Max Row Max Row Max Row Max Row 

    ' This code will handle multiple header rows 
    For RowSht1Crnt = 1 To RowSht1DataFirst - 1 
     ColSht2Crnt = ColSht2Dest 
     For ColSht1Crnt = ColSht1TempFirst To ColSht1TempLast 
     ' Merge two cells together ready for column name 
     .Range(.Cells(RowSht2Crnt, ColSht2Crnt), _ 
       .Cells(RowSht2Crnt, ColSht2Crnt + 1)).Merge 
     With .Cells(RowSht2Crnt, ColSht2Crnt) 
      .Value = ShtValue(RowSht1Crnt, ColSht1Crnt) 
      .HorizontalAlignment = xlCenter 
     End With 
     ColSht2Crnt = ColSht2Crnt + 2 
     Next 
     RowSht2Crnt = RowSht2Crnt + 1 
    Next 
    ' Now add "Max Row Max Row Max Row Max Row" row 
    ColSht2Crnt = ColSht2Dest 
    For ColSht1Crnt = ColSht1TempFirst To ColSht1TempLast 
     With .Cells(RowSht2Crnt, ColSht2Crnt) 
     .Value = "Max" 
     .HorizontalAlignment = xlRight 
     End With 
     ColSht2Crnt = ColSht2Crnt + 1 
     With .Cells(RowSht2Crnt, ColSht2Crnt) 
     .Value = "Row" 
     .HorizontalAlignment = xlRight 
     End With 
     ColSht2Crnt = ColSht2Crnt + 1 
    Next 
    RowSht2Crnt = RowSht2Crnt + 1 

    ' Now create data row 
    ColSht2Crnt = ColSht2Dest 
    For ColSht1Crnt = ColSht1TempFirst To ColSht1TempLast 
     .Cells(RowSht2Crnt, ColSht2Crnt).Value = TempMaxByCol(ColSht1Crnt) 
     ColSht2Crnt = ColSht2Crnt + 1 
     .Cells(RowSht2Crnt, ColSht2Crnt).Value = RowForMaxTemp(ColSht1Crnt) 
     ColSht2Crnt = ColSht2Crnt + 1 
    Next 
    End With 

End Sub 

Редактировать Добавление потому что ОП хочет, чтобы выбрать столбцы, из которых максимальные значения должны быть выбраны.

Если я правильно понял ваш комментарий правильно:

  • Число строк устанавливается на 30.
  • Вы хотите, чтобы выбрать столбцы, из которых максимумы должны быть извлечены во время выполнения.

Приведенный выше код обрабатывает любое количество строк. Я предлагаю вам оставить это без изменений, даже если вы считаете, что номер будет всегда 30.В течение моей карьеры я слышал, что «это требование никогда не может меняться» много раз, чтобы услышать год или два позже «Извините, это изменилось».

Был один аспект вышеприведенного кода, который, как я думал, был слабым, но который я не хотел исправлять, потому что он бы добавил осложнения, которые не хотели объяснять. Я использовал .UsedRange для загрузки данных с рабочего листа. Это самый простой способ, но определение .UsedRange не всегда соответствует ожидаемому. .UsedRange включает строки и столбцы, которые были отформатированы (например, изменена высота или ширина), но в противном случае они не используются. В этом answer of mine к более раннему вопросу я включаю макрос, который демонстрирует ряд методов для поиска окончательной строки или столбца и показывает, где каждый метод терпит неудачу. Я не думаю, что это важно для вашего текущего вопроса, но я предлагаю вам сохранить этот макрос и поэкспериментировать с ним позже.

Рассмотрим этот макрос:

Sub TestGetRange() 

    Dim CalcRange As Range 
    Dim Reply As Long 

    Do While True 
    Err.Clear 
    On Error Resume Next 
    Set CalcRange = Application.InputBox(Prompt:="Select columns to be copied", _ 
             Title:="Extract maximum temperatures", Type:=8) 
    On Error GoTo 0 
    If Err.Number <> 0 Then 
     Reply = MsgBox(Prompt:="Do you wish to exit without extracting any temperatures?", _ 
        Buttons:=vbYesNo, Title:="Extract maximum temperatures") 
     If Reply = vbYes Then 
     ' User wants to exit 
     Exit Do 
     End If 
     ' Loop for another go 
    Else 
     ' User had entered a valid range 
     Exit Do 
    End If 
    Loop 

    If CalcRange Is Nothing Then 
    Debug.Print "User wants immediate exit" 
    Exit Sub 
    Else 
    Debug.Print CalcRange.Address 
    End If 

End Sub 

Как я уже говорил ранее, если пользователь нажмет Отменить, есть синтаксическая ошибка времени выполнения, и пользователь должен выбрать Debug и нажмите F5 к Продолжать. Это тип ситуации, для которой подходит On Error Resume Next. Я добавил это к вашему исходному коду и включил опцию выхода. Этот макрос не использует введенный диапазон, кроме отображения его адреса.

Использование Ctrl + Left Mouse вы можете выбрать несмежные диапазоны. Вы не говорите, хотите ли вы выбирать столбцы 4, 5, 11 и 12, но поскольку вы не можете остановить выбор пользователем несмежных диапазонов, я включил код для их обработки.

Я использовал этот макрос несколько раз. В первый раз, когда я выбрал столбцы B и C, в следующий раз, когда я отменил, я выбрал различные смешанные диапазоны. Выход был:

$B:$C 
User wants immediate exit 
$B$1,$D$1 
$B$1,$C$1,$E$1 
$B$1:$D$1 
$B:$B,$E:$E 
$B:$C,$E:$E,$F:$F,$H:$H 
$B:$B,$E$2 

Обратите внимание, что я получаю $B:$B или $B:$C, если выбрать столбцы и $E$1, если выбрать ячейку. В последней строке я выбрал и столбец, и ячейку.

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

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

Добавьте этот код в нижней части выше макроса:

Dim Count As Long 
    Dim RngCrnt As Range 

    Count = 0 
    For Each RngCrnt In CalcRange 
    Debug.Print " " & RngCrnt.Address 
    Count = Count + 1 
    If Count = 10 Then 
     Exit For 
    End If 
    Next 

    Debug.Print CalcRange.EntireColumn.Address 
    For Each RngCrnt In CalcRange.EntireColumn 
    Debug.Print " " & RngCrnt.Address 
    Count = Count + 1 
    If Count = 10 Then 
     Exit For 
    End If 
    Next 

В этом коде я использовал For Each заявление, чтобы разделить диапазон от пользователя в поддиапазонах. Я управлял макрокоманду, выбранные столбцы В и С и получили следующий результат:

$B:$C 
    $B$1 
    $C$1 
    $B$2 
    $C$2 
    $B$3 
    $C$3 
    $B$4 
    $C$4 
    $B$5 
    $C$5 
$B:$C 
    $B:$B 
    $C:$C 

С первым For Next, суб-диапазон представляет собой клетку. Если бы я пропустил код, ограничивающий вывод до 10, я бы получил одну строку отображения на ячейку в каждом столбце.

Во втором For Next, я скорректировал диапазон пользователей, добавив .EntireColumn. Это не влияет на адрес, отображаемый Debug.Print CalcRange.EntireColumn.Address, но изменил поддиапазон на столбец, который я хочу.

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

Sub ExtractMaxTemperatures2() 

    ' Adjusted to handle user selected columns 

    Const RowSht1DataFirst As Long = 2 ' First non-header row in Sheet1 
    Const ColSht2Dest As Long = 2   ' Left column \ of table of extracted 
    Const RowSht2Dest As Long = 3   ' Top row / values in Sheet2 

    Dim ColLogicalCrnt As Long   ' 1, 2, 3 and so on regardless of true column number 
    Dim ColSht1Crnt As Long    ' Current column within Sheet1 
    Dim ColSht2Crnt As Long    ' Current column within Sheet2 
    Dim NumColsSelected As Long   ' Number of columns selected. 
    Dim Reply As Long      ' Return value from InputBox 
    Dim RowForMaxCrnt As Long    ' Row holding maximum temperature found so far within current column 
    Dim RowSht1Crnt As Long    ' Current row within Sheet1 
    Dim RowSht2Crnt As Long    ' Current row within Sheet2 
    Dim RngColCrnt As Range    ' Sub-range of user selected range giving current column 
    Dim RngUserSelected     ' Range selected by user then adjusted with .EntireColumn 
    Dim ShtValue As Variant    ' 2D array holding values loaded from Sheet1 
    Dim TempCrnt As Single    ' The temperature from the current cell 
    Dim TempMaxCrnt As Single    ' Maximum temperature found so far within current column 

    ' Declare arrays to hold the maximum temperature and its row for each column. 
    ' These arrays will be sized at runtime. 
    Dim TempMaxByCol() As Single   ' Maximum temperature for each logical column 
    Dim RowForMaxTemp() As Long   ' Row for maximum temperature for each logical column 

    With Worksheets("Sheet1") 
    ShtValue = .UsedRange.Value 
    .Activate  ' Necessary to ensure Sheet1 visible for range selection 
    End With 

    Do While True 
    Err.Clear 
    On Error Resume Next 
    Set RngUserSelected = Application.InputBox(Prompt:="Select columns to be copied", _ 
             Title:="Extract maximum temperatures", Type:=8) 
    On Error GoTo 0 
    If Err.Number <> 0 Then 
     Reply = MsgBox(Prompt:="Do you wish to exit without extracting any temperatures?", _ 
        Buttons:=vbYesNo, Title:="Extract maximum temperatures") 
     If Reply = vbYes Then 
     ' User wants to exit 
     Exit Do 
     End If 
     ' Loop for another go 
    Else 
     ' User had entered a valid range 
     Exit Do 
    End If 
    Loop 

    If RngUserSelected Is Nothing Then 
    Debug.Print "User wants immediate exit" 
    End If 

    ' Convert any cells to columns 
    Set RngUserSelected = RngUserSelected.EntireColumn 

    ' Count number of selected columns 
    NumColsSelected = 0 
    For Each RngColCrnt In RngUserSelected 
    NumColsSelected = NumColsSelected + 1 
    Next 

    ' Size arrays for number of selected columns 
    ReDim TempMaxByCol(1 To NumColsSelected) As Single 
    ReDim RowForMaxTemp(1 To NumColsSelected) As Long 

    ' Fill TempMaxByCol and RowForMaxTemp with extracted values 
    ColLogicalCrnt = 0 

    ' Loop for each temperature column 
    For Each RngColCrnt In RngUserSelected 

    ColSht1Crnt = RngColCrnt.Column 
    ColLogicalCrnt = ColLogicalCrnt + 1 ' Logical column for this physical column 

    RowForMaxCrnt = 0   ' Indicates no temperature saved yet 

     ' Loop for each data row column. UBound(ShtValue, 2) identifies the last row. 
     For RowSht1Crnt = RowSht1DataFirst To UBound(ShtValue, 1) 
     If IsNumeric(ShtValue(RowSht1Crnt, ColSht1Crnt)) Then 
      ' This cell is numeric 
      TempCrnt = Val(ShtValue(RowSht1Crnt, ColSht1Crnt)) 
      If RowForMaxCrnt <> 0 Then 
      ' A possible maximum temperature has already been stored. 
      ' Check current value against it. 
      If TempMaxCrnt < TempCrnt Then 
       ' Higher temperature found. Store details in temporary variables 
       RowForMaxCrnt = RowSht1Crnt 
       TempMaxCrnt = TempCrnt 
      End If 
      Else 
      ' First temperature found. Store details in temporary variables 
      RowForMaxCrnt = RowSht1Crnt 
      TempMaxCrnt = TempCrnt 
      End If 
     End If 
     Next 
     'Move values from temporary variables to arrays 
     TempMaxByCol(ColLogicalCrnt) = TempMaxCrnt 
     RowForMaxTemp(ColLogicalCrnt) = RowForMaxCrnt 

    Next 

    ' Initialise the current row to the start row of the outout table 
    RowSht2Crnt = RowSht2Dest 

    ' I think you call the destination sheet "Calc" but I have used "Sheet2" 

    With Worksheets("Sheet2") 

    ' Create header lines 
    ' TC1  TC2  TC3  TC4 
    ' Max Row Max Row Max Row Max Row 

    ' This code will handle multiple header rows 
    For RowSht1Crnt = 1 To RowSht1DataFirst - 1 
     ColSht2Crnt = ColSht2Dest 
     ColLogicalCrnt = 0 
     For Each RngColCrnt In RngUserSelected 
     ColSht1Crnt = RngColCrnt.Column 
     ColLogicalCrnt = ColLogicalCrnt + 1 ' Logical column for this physical column 
     ' Merge two cells together ready for column name 
     .Range(.Cells(RowSht2Crnt, ColSht2Crnt), _ 
       .Cells(RowSht2Crnt, ColSht2Crnt + 1)).Merge 
     With .Cells(RowSht2Crnt, ColSht2Crnt) 
      .Value = ShtValue(RowSht1Crnt, ColSht1Crnt) 
      .HorizontalAlignment = xlCenter 
     End With 
     ColSht2Crnt = ColSht2Crnt + 2 
     Next 
     RowSht2Crnt = RowSht2Crnt + 1 
    Next 
    ' Now add "Max Row Max Row Max Row Max Row" row 
    ColSht2Crnt = ColSht2Dest 
    ' ColLogicalCrnt = 0  ' Don't need logical column for this loop 
    For Each RngColCrnt In RngUserSelected 
     ColSht1Crnt = RngColCrnt.Column 
     With .Cells(RowSht2Crnt, ColSht2Crnt) 
     .Value = "Max" 
     .HorizontalAlignment = xlRight 
     End With 
     ColSht2Crnt = ColSht2Crnt + 1 
     With .Cells(RowSht2Crnt, ColSht2Crnt) 
     .Value = "Row" 
     .HorizontalAlignment = xlRight 
     End With 
     ColSht2Crnt = ColSht2Crnt + 1 
    Next 
    RowSht2Crnt = RowSht2Crnt + 1 

    ' Now create data row 
    ColSht2Crnt = ColSht2Dest 
    ColLogicalCrnt = 0 

    ' Loop for each temperature column 
    For Each RngColCrnt In RngUserSelected 
     ' ColSht1Crnt = RngColCrnt.Column ' Don't need Sheet 1 column for this loop 
     ColLogicalCrnt = ColLogicalCrnt + 1 ' Logical column for this physical column 
     .Cells(RowSht2Crnt, ColSht2Crnt).Value = TempMaxByCol(ColLogicalCrnt) 
     ColSht2Crnt = ColSht2Crnt + 1 
     .Cells(RowSht2Crnt, ColSht2Crnt).Value = RowForMaxTemp(ColLogicalCrnt) 
     ColSht2Crnt = ColSht2Crnt + 1 
    Next 
    End With 

End Sub 
+0

Большое спасибо Тони !, это было очень поучительно. Я рад, что вы помогли мне не только ответить на этот вопрос, но и научить меня. Читая ответ, я вижу, что у меня долгий длинный путь ... Извиниться за то, что я не выражаю себя ясно, английский не мой родной язык, и мои знания основаны на vb. – Jero

+0

Что касается кода, вы получили почти все, что я хотел сделать, но одна из моих проблем заключается в том, что я никогда не использую такое же количество столбцов. Строковые данные всегда содержат одинаковое количество из них (30), но я не хочу показывать их все в «sheet2», только те, которые мне нужны иногда 10 других 12 и т. Д. Вот почему я хотел выбрать вручную до. Но даже не знаю, можно ли это сделать. Cheers – Jero

+0

Я забыл маленький неанглийский, которого я когда-либо знал, поэтому не могу никого критиковать. Ваш английский был в порядке. Трудно точно объяснить, что вы хотите, даже на своем родном языке. –

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