Это мой первый пост. Я пытался найти похожую тему, но не нашел.
Я новичок в VBA, и я учусь, пытаясь создать файл, который помогает спланировать вырезание частей из основной части.
Поскольку Excel VBA не позволяет рисовать фигуры или линии, я использую метки с рамкой для создания прямоугольников.
Прямоугольники обозначают разрезы, которые необходимо сделать.
Моя основная форма выглядит так:
Как вы можете видеть на изображении, в области, обозначенной красным прямоугольником, большой кусок размером 1600 мм (в этом примере) будет иметь семь разрезов по 60 мм.
Моя проблема началась, когда я попытался добавить различные разрезы в свой план резки. Когда я принимаю разрез, он попадает в очередь резки, и можно определить новый разрез, как показано на изображении ниже:
Проблема в том, что первый разрез должен остаться там. Я понял, что для этого нужно использовать Коллекции и, скорее всего, Классы. Это особенно важно, поскольку я хочу, чтобы в очереди была возможность перемещать каждую строку вверх и вниз по очереди или даже стирать строку (и отражать ее в моем «рисунке»).
Код на данный момент слишком обширен, чтобы добавить его сюда, но мне удалось добавить некоторые функции, которые будут описаны ниже. Некоторые имена на португальском, но я не думаю, что это представляет проблему.
Здесь я создаю разрезы, определенные Ларгура: и Cortes reais:
Option Explicit
Public iCuts As Integer
Public Labels As Collection
Public newLabel As Object
Public bRecalculate As Boolean
Sub DrawCuts(NCuts As Integer, CutWidth As Double, TotalWidth)
Dim OriginX, OriginY As Integer
Dim labelCounter As Long
Dim labelCollection As New Collection
OriginX = 372
OriginY = 24
CutWidth = Multiplier(CutWidth, TotalWidth)
For labelCounter = 0 To NCuts - 1
Set newLabel = frmPlanning.Controls.Add("Forms.Label.1", "Corte" & labelCounter, True)
With newLabel
.ControlTipText = .Name 'labelCounter + 1
.Left = OriginX + CutWidth * labelCounter
.Width = CutWidth
.Height = 48
.Top = OriginY
.BackColor = &HFFFFFF
.BorderStyle = 1
.TextAlign = 2
.Font.Size = 6
.Caption = iCuts
End With
iCuts = iCuts + 1
Next
iCuts = iCuts - 1
End Sub
И в следующей SUB я адаптирую разрезы к размеру основной части, определяемой Ларг. бобин:.
Sub Dim_Labels(Cuts As Integer, CutWidth As Double, RollWidth As Double, RollLeft As Double)
With frmPlanning.lCutWidth
.Caption = CutWidth * Cuts
.Width = Cuts * Multiplier(CutWidth, RollWidth)
End With
With frmPlanning.lCutLeft
.Caption = RollLeft
.Left = 372 + Cuts * Multiplier(CutWidth, RollWidth)
.Width = 320 - Cuts * Multiplier(CutWidth, RollWidth)
End With
frmPlanning.lRollWidth = RollWidth
End Sub
Я попытался поместить это в коллекцию, но я не только получаю всевозможные ошибки, но я также не могу создавать разные коллекции для каждого набора разрезов, чтобы перемещать каждый набор независимо.
Я знаю, что это связано с моим непониманием того, как работают коллекции и классы, но я действительно застрял и не могу двигаться дальше, и мне нужна помощь, если вы можете ее дать.
Я не смог найти способ, но могу предоставить файл Excel, чтобы помочь вам лучше понять проблему, если есть способ.
Спасибо. Жулио
@RikSportel, спасибо за ответ. Да, но не уверен, что я правильно понял ваш пункт B, и, чтобы уточнить, второй, третий, ... разрезы могут иметь разную ширину, хотя все разрезы внутри партии будут иметь одинаковую ширину.
Да, это был пункт Б. Но после добавления всех «партий» они должны уместиться в большой коробке, правильно?
Да, в конце концов, все они должны поместиться в большую коробку.





Итак, я думаю, это то, что вам нужно. Обратите внимание, что это не самый чистый код, но он выполняет отдельные части рисования в пользовательской форме.
Во-первых, я сохранил OriginX и OriginY в самой пользовательской форме - в конце концов, он должен контролировать, где должно начинаться рисование. Код пользовательской формы:
Public OriginX As Integer
Public OriginY As Integer
Private Sub UserForm_Initialize()
OriginX = 20
OriginY = 20
End Sub
Затем я создал класс BigBox для красного прямоугольника, который у вас был. У него есть высота, ширина, и при инициализации он добавит метку в пользовательскую форму. (Обратите внимание, что размещение метки в форме таким образом - плохая практика - класс не должен знать, где его нарисовать. Однако - для ответа на ваш вопрос это не актуально сразу.)
Класс BigBox:
Private p_width As Integer
Private p_height As Integer
Private p_label As MSForms.Label
Public Property Let Width(value As Integer)
p_width = value
p_label.Width = p_width
End Property
Public Property Get Width() As Integer
Width = p_width
End Property
Public Property Let Height(value As Integer)
p_height = value
p_label.Height = p_height
End Property
Public Property Get Height() As Integer
Height = p_height
End Property
Public Property Get Label() As MSForms.Label
Set Label = p_label
End Property
Private Sub Class_Initialize() 'This bit is bad practice, but it works:
Set p_label = frmPlanning.Controls.Add("Forms.Label.1", "BigBox", True)
p_label.Left = frmPlanning.OriginX
p_label.Top = frmPlanning.OriginY
p_label.BorderColor = Red
p_label.BorderStyle = 1
End Sub
Затем я создал класс «Cut», который можно использовать в коллекции с разрезами, поэтому, когда вам нужно перерисовать, вы сохраните их / они не будут забыты:
Класс резки:
Private p_width As Integer
Private p_height As Integer
Public Property Let Width(value As Integer)
p_width = value
End Property
Public Property Get Width() As Integer
Width = p_width
End Property
Public Property Let Height(value As Integer)
p_height = value
End Property
Public Property Get Height() As Integer
Height = p_height
End Property
Затем я изолировал коллекции «Cuts» и «Labels», так как метки нужно удалить и перерисовать, когда вы добавите второй пакет. Следующая процедура
Код модуля1:
Option Explicit
Public bb As BigBox
Public cuts As Collection
Public cutLabels As Collection
Public totalCutsWidth As Integer
Public piece As Cut
Sub test2()
If cuts Is Nothing Then
Set cuts = New Collection
End If
If cutLabels Is Nothing Then
Set cutLabels = New Collection
End If
frmPlanning.Show vbModeless
Set bb = New BigBox
bb.Height = 100
bb.Width = 500
AddCuts 5, 20
AddCuts 10, 10
AddCuts 7, 50
End Sub
Sub AddCuts(numberOfCuts As Integer, widthOfCuts As Integer)
Dim i As Integer
If numberOfCuts <= 0 Then Exit Sub
For i = 1 To numberOfCuts
Set piece = New Cut
piece.Width = widthOfCuts
piece.Height = bb.Height
totalCutsWidth = totalCutsWidth + widthOfCuts
If totalCutsWidth <= bb.Width Then
cuts.Add piece
End If
Next i
DrawCuts
End Sub
Sub DrawCuts()
Dim i As Integer
Dim OffsetX As Integer
Dim newLabel As MSForms.Label
OffsetX = 0
For i = cutLabels.Count To 1 Step -1
frmPlanning.Controls.Remove "Corte" & i
cutLabels.Remove i
Next i
i = 0
OffsetX = frmPlanning.OriginX
For Each piece In cuts
i = i + 1
Set newLabel = frmPlanning.Controls.Add("Forms.Label.1", "Corte" & i, True)
With newLabel
.ControlTipText = .Name
.Left = OffsetX
.Width = piece.Width
.Height = piece.Height
.Top = frmPlanning.OriginY
.BackColor = &HFFFFFF
.BorderStyle = 1
.TextAlign = 2
.Font.Size = 6
.Caption = i
OffsetX = OffsetX + piece.Width
End With
cutLabels.Add newLabel
Next piece
End Sub
Обратите внимание, что добавление разрезов гарантирует, что разрезы по-прежнему помещаются в большую рамку, и что рисунок разрезов отделен от него. Кроме того, если следующий кусок больше не помещается в коробке, он не будет добавлен. Т.е. если большая коробка имеет ширину 500, и вы добавляете 10 разрезов шириной 25, а затем 11 разрезов шириной 30, он добавит только первые 8 из второй партии (10 * 25 = 250, 8 * 30 = 240, 240 + 250 = 490, поэтому 9-й, 10-й и 11-й не помещаются в общую ширину 500, поэтому не будут добавлены.
Надеюсь, это поможет и достаточной информации для включения в существующее решение.
Привет, Рик. Вы молодцы только благодаря своей работе. Думаю, отсюда я справлюсь. Я попробую код и вернусь к вам, как только он будет работать над моим файлом (надеюсь). Спасибо.
Привет, @RikSportel, извиняюсь за поздний ответ. У меня не было времени на это смотреть (приоритеты постоянно меняются!) ... У меня нет слов, чтобы поблагодарить вас. Код прекрасно работает. Мне пришлось внести некоторые незначительные изменения, чтобы интегрировать его в существующий код, но он работал нормально. Благодаря этому я также узнал, как работают классы и коллекции, и теперь понимаю их намного лучше. У меня все еще есть некоторые проблемы, которые нужно решить, но это больше вопрос организации моего кода, чем чего-либо еще. Еще раз спасибо за вашу помощь. С уважением.
Правильно ли я резюмирую это, когда говорю, что вам нужны: A.
Xразрезает ширинойw, где TotalCutsWidth (X * w) не превышает ширину большого блока (красный прямоугольник) (TotalWidth) B. Затем добавьте второй (третий, четвертый) массив таких разрезов (скажем: Y), который нужно складывать несколько раз. C. TotalCutsWidth для всех групп вместе взятых разрезов тоже не должно превышать TotalWidth? В итоге: пользователь может точно определить, сколько частей какой ширины он хочет из общего красного прямоугольника, и это должно быть нарисовано с помощью меток в этом верхнем правом поле?