VBA Excel 2003/2007: Declaring, Filling, and Passing a Jagged Array - vba

I have thoroughly researched this topic and have yet to find code that works to accomplish what I need to do. In a nutshell, I'm creating a Production Tracking program and the feature of it on which I'm working now involves accurately tracking vacation days for 5 employees. A userform containing 5 listboxes, one for each employee, is used to select which days each employee took off for the week. The problem comes when I try to create unique dynamic arrays containing each employees' days off. I figured out how to create an array that captures this information but it's one array that gets reassigned each time the loop iterates. I need to have a unique array for each employee containing his days off to be used later in the code to adjust weekly scoring depending on his available days of work. Below is my code in the userform for to create a create the jagged array:
Public Name_Jagged() As Variant
For Each Name In Name_Array
Set Unique_Listbox = Controls(Name & "_Vacation")
For UnSelected = 0 To Unique_Listbox.ListCount - 1
If Unique_Listbox.Selected(UnSelected) = False Then
ReDim Preserve Name_Jagged(0 To UBound(Name_Jagged) + 1)
Name_Array(Name) = Name_Jagged()
Name_Jagged(UBound(Name_Jagged)) = Unique_Listbox.List(UnSelected)
End If
For UnSelected_Array_Pos = LBound(Name_Jagged) To UBound(Name_Jagged)
MsgBox Name & "_" & Name_Jagged(UnSelected_Array_Pos)
Next UnSelected_Array_Pos
Next UnSelected
Next Name
The compiler will not allow me to use Public Name_Jagged()() As Variant either despite most other forums saying this is how it's supposed to be written. The only other post I found online regarding this jagged array declaration issue was not answered.
I would really appreciate your help. I've been able to figure out everything so far from previous threads but this has eluded me. If there is a better option than jagged arrays to accomplish this, I'm all ears. I read in some forums about using Lists but I am not at all familiar with them or how to use them at this point. Thanks in advance for the help.

Just a thought but why have 5 static listboxes for each employee?
Why not just have 1 list box which contains the names of the employees and 1 list box which contains the days of the week. You highlight the employee you want and than select the days which they've taken off. Hit a submit button which would load the employees name into an array with the days selected? The array could be structured like this
NAME | MONDAY | TUESDAY | WEDNESDAY | THURSDAY | FRIDAY | SATURDAY | SUNDAY
JIM..... OFF............ OFF
ERIC.......................OFF.............OFF
And so on. This way if you need to add people in the future you just add them to the list box. You would than have one simple array to deal with?
Also you said "to be used later in the code to adjust weekly scoring depending on his available days of work"
A suggestion; You may want to consider logging it to a simple mysql/mssql database which gives you far more flexibility and control for the future.

Related

Remove objects like table row before rendering

I am generating a document with itext7 in vb.net. The document is a payment reminder. The document contains 1 to many positions (I do not know how many positions the document will have at the end). Sometimes it could happen, that a position contains no amount. And I want to remove this position.
The reminder positions looks for example like this:
CustomerName | Amount |
---------------|-------------|
Jupiter Jones | 1,100.12 |
Peter Crenshaw | 0.00 |
Bob Andrews | 231.02 |
---------------|-------------|
Sum | 1,331.14 |
The lines are added to the table with
table.AddCell(cell1)
table.AddCell(cell2)
This example is very simplified...sadly it is because of the data structure and the calculations that have to be made, that I do not know whether the position line has to be printed before starting the line (the first cell of the line) or not.
So is it possible to "remember" a kind of index or handle or anything else, so that I am able to remove certain objects from the itext7 document before I "send" it to the renderer?
The table should look like this after the "removement":
CustomerName | Amount |
---------------|-------------|
Jupiter Jones | 1,100.12 |
Bob Andrews | 231.02 |
---------------|-------------|
Sum | 1,331.14 |
I hope you understand, what I mean...
To clarify some facts and answer the questions blow:
I wrote a wrapper-class (dll) for itext7 to create different types of pdfs with it. A whole table-creation contains of
obj.TableBegin({Cell1Width, Cell2Width})
while objMySqlDataReader.Read
Dim calculatedAmount as Single = 0
//do some calculations
objCell1.Text = objMySqlDataReader("CustomerName")
objCell2.Text = calculatedAmount
obj.TableCreateRow({objCell1, objCell2})
End While
obj.TableEnd()
Method TableBegin
Private Sub TableBegin(ByVal ColWidths as Single())
table = new Table(ColWidths)
//some formattings and so on
End Sub
Method TableCreateRow
Private Sub TableCreateRow(byval arrCells as MyOwnCellType())
For Each varCell As MyOwnCellType In arrCells
Dim c As Cell = New Cell()
Dim p As Paragraph = New Paragraph(varCell.Text)
c.Add(p)
//followed by some formatting lines like c.SetBackgroudColor
//or c.SetBorder
table.AddCell(c)
Next
End Sub
Method TableEnd
Private Sub TableEnd()
document.Add(table)
End Sub
The moment when I know whether a row as to be printed or not is variable. Sometimes I know it just after "printing" both cells of the row. But it could happen that I want to remove a table-row after the table has been "finished".
In another "document-type" a have a very similar problem, but there I need to remove a whole page of the document including Paragraphs, Tables, Images....
My utopian idea was, that I "save" the handle of each "possible to be removed object" in a list or array and after recognizing wheter the objects have to be printed or not I can either clear this array or remove all objects within this array by something like document.remove(handle)
Another utopian idea was, that I "collect" all "possible to be removed / printed objects" in any kind of array or list and after recognizing whether printing or not I can "push" these objects to the document or discard them.
It is difficult to discribe and even much more difficult to understand why I do not know "printing or not" before printing. But believe me - I do not know earlier. ;-)
Any idea or help is very appreciated.

Tabulating a final score for a questionnaire

Thanking in advance for your help with this one. I have searched everywhere but haven't been able to find an answer that addresses my issue.
Here is the background:
I have a questionnaire with 15 questions for which the possible answers are “Y”, “N” or “N/A”. For each question, I have assigned to the “Y” a value and to the “N” and “N/A” a zero.
I need a macro that will, for the active row in question, identify the heading of each question (1-15), look up each heading on a different worksheet in the same file, locate the number assigned to it if the answer is either “Y” or “N” (ignore the “N/A”s) and add all those numbers for the base score.
Then, as a second step, the macro will add only the “Y” answers and tabulate them against the base score for a final score.
For illustration purposes let’s say that I have the following questions:
Table Chair Lamp Plant
Y Y N N/A
In a different tab, the table looks like this:
Table Chair Lamp Plant
5 10 8 15
I need a macro that will look at the column headings to match them, and then at the values assigned to table, chair and lamp (ignore plant since N/A), add them (for a total of 23). Then add only the Ys (for a total of 15) and then produce a final score of 65 (15 out of 23 or 65%).
Really stuck with this one… I have no idea how to even start… any help is truly appreciated.
Thank you so much!!!!
Marta
When you have a big task in front of you, you need to divide it up incrementally. Stack Overflow isn't here to write your macro for you.
The first part you want to do is match the column headers in the Active Row with the column headers on another worksheet, right? What I've posted below should get you the column headers on the question sheet and read them off to you. Try it out and take it further (do some googling if you need to). When you run into a problem with the code you make, that's where a question should be asked.
(Place this code into a fresh module in your workbook, and connect it to a button or something on the questionnaire worksheet)
Public Sub TallyQuestions()
Dim questionSht As Worksheet
Set questionSht = Sheets("Worksheet that has the questions you were talking about") 'replace name with name of questionSht
Dim questionShtColHeaders As Range, cell As Range
Set questionShtColHeaders = questionSht.Range("A1:A15")
For Each cell In questionShtColHeaders
MsgBox cell.Value
Next cell
End Sub

How can I make the same set of conditional statements apply across all subroutines in vba?

thank you very much to those who answered my original question. I'd like to go into a little more detail about the problem I am having. I am working on a macros that provides a visual representation of the 4 different production phases of a product we produce. The spreadsheet is set up to appear as a linear calendar, showing all 365 days of the year and grouping them into calendar weeks. Each production phases has a different color associated with it. The four buildphases are:
1) Assembly: 1 day (yellow)
2) Initial analysis: 1 day (purple)
3) In-depth analysis: 7 days (green)
4) Shipping: 1 day (red)
No work is performed in the facility on weekends or holidays. Saturdays and sundays are represented by a cell colored black and holidays are represented by cells colored orange and having a criss cross pattern. The macro is designed to skip these holidays using the following if then statement:
Dim i As Integer
i = Analysis days
for i = 1 to 7
ActiveCell.Select
If Selection.Interior.Pattern = x1CrissCross And Selection.Interior.Color = orange Then
ActiveCell.Offset(0, 1).Select
Else: ActiveCell.Select
End If
If Selection.Interior.Color = black Then
ActiveCell.Offset(0, 2).Select
Else: ActiveCell.Select
End If.
The If Then statement that tells the macro to skip Saturday and Sunday works every time. But the statement that tells the macro to skip holidays only works part of the time, and if the holidays last longer than a few days (Christmas vacation lasts nine days) the macro inserts production work days interspersed throughout the holiday. I've found that by copying and pasting the above statements directly beneath one another several times seems to fix the issue. But I am sure there has to be a more efficient way to do this. Does anyone know of a way I can fix the issue without having to copy and paste the same lines of code mulitple times?
Thanks in advance!
If you are looking for a way for make a test and store the result globally in your code, so also in the other functions/subs you can access the data prevoiusly tested take a look here.
If you are lookin to a way to compact your code and write something like
b = check(a)
instead of
if a="xx" then
b = "something"
else
b = "something else"
end if
take a look to this link for functions/subs explanations

Today function equivalent in VBA in combination with countifs

I am having some problem with using a countifs formula in Excel / VBA. I have got the formula working perfect in Excel but ideally I want to use this in VBA with my form. Here is the formula in Excel which works a treat:
=COUNTIFS(Sheet1!A:A,"Place",Sheet1!K:K,"<"&TODAY())
will count the names places that are now in the past
=COUNTIFS(Sheet1!A:A,"place",Sheet1!K:K,">"&TODAY())
will count the names places that are current
I have five different Places in column A and hundreds of different dates in column K. The above formulas work well in Excel and return the correct values. I have spent hours trying to get this to work in VBA with my userform but keep getting various errors. The first part is not the problem but as soon as I get to the &today function it falls apart. From what I can see the &today function is not available in VBA and the &Date seems to be the recommendation. I have tried this but still get no where. I'm missing a trick (or several) here and I would really like to get this working in VBA rather than using the current formulas in Excel. The returned results are then displayed in textboxes on my form.
All ideas and feedback much welcome!
Second edit
================================
Thanks for the quick replies! Here is the actual code I am playing about with in VBA
'Count events by area'
Dim ListLondon As Long
ListLondon = .CountIf(Range("a1:a1998"), "London"), ("Sheet1!K1:K1998"), "<" & Date)
End With
Me.TextBox1 = ListLondon
I know the second part of the count if is all wrong regards the date - that's how I've left it for now. I am really hoping to use the current layout and a working Date / Today code at the end. Please show me what I've done wrong here!
====
oops - can see a mistake already - but the initial problem remains around the date issue. I should of used countifs as using multiple criteria.
You have to read the values of the cells to your VBA code. I recommend you to use Excel.Range object to do that. It can interpret the range like the edit line of the Excel, something like
Dim foo as Excel.Range
set foo = yourworksheet.Range("A1:B3")
Read the Date type data into VBA Date type variable by iterating through the cells.
Examine relation between the read data and the current date. Current date can be read by using the DateTime.Now function.
Increment a variable based on a decision

Development DropDowns List error on empty value

I have a simple dropdown list named DD8. It uses 50 rows as control, the problem is that for now only 45 rows are used. That means that in the dropdown list there are 5 empty rows. The problem is that if someone select one empty row, or don't select anything (default is empty) the fallowing code will show error :
With Worksheets(1)
NameProf = .DropDowns("DD8").List _
(.DropDowns("DD8").ListIndex)
End With
I tried things like if .DropDowns("DD8").List (.DropDowns("DD8").ListIndex) != "" but ofc, it shows error. I searched how to select only used rows with the DropDown list of the development tab but it doesn't seem to be possible.
I have to select 50 rows because new customers can be added.
Do you know how it can be achieved ?
If new customers can be added, then I imagine, and hope for you, that it goes above 50.... so it's not just an issue of having 5 blanks for now to not be an option, but also allowing customers 50-2,483 also be on there when they come along. ---- Without more details on your code, I believe this suggestion should help 'guide' you but not immediately solve your issue.
Essentially, whenever you call to have your dropdown populated, you want some code to find the last row of data in the customers column, and then assign your dropdown to populate with the starting row of your customers to the lastrow. This way no matter how many customers you have 2, 48, 189... they will show in your dropdown without that issue occurring. A simple google search will yield how to find the last row in excel.
Sorry I couldn't just bust out the code to make it work for you right this second, but I think this should be a good starting point for you.