Ultimately I'm going to want to make a whole bunch of checkboxes enabled&unlocked/disabled&locked based on which values are checked in a multi-select lookup, and how many are allowed. To do this, first I need to know how to get at the data in these multi-select lookups through vba. I imagine.
I've tried to set a variable in vba to the value of one of these fields, but the only data type it seems to accept is variant - and even then I can't get the immediate window to tell me what I've collected into that variable.
I need vba to be able to work out if a certain label is one of the ones listed in the multi-select field.
Now for further explanation/context, real examples: Lets say you can pick colours for a book based on what author and genre the book "owns". Each author and genre has a variable number of colours you can pick, and a limited range.
Lets say the book is by Bob, who is allowed an 2 of red, blue, orange and yellow, and it's a fantasy book, which can be 3 of red, white, grey, black and purple.
All of the checkboxes on the form for red, blue, yellow, orange, white, grey, black and purple become enabled and unlocked, while all the rest remain locked and disabled as they aren't available at all.
The user selects red - no change, except for that box being selected.
The user also selects blue - no change, except for that box being
selected, because while 2 (max allowed) of bob's colours are
selected, red is also on the fantasy list, which still has 2
remaining. The overlap saves more.
The user de-selects red, and selects yellow - red is still available
(fantasy) but orange is now disabled and locked.
The user selects red, white and purple - grey and black are disabled
and locked, as all options have now been exhausted.
Now, if you want to start me on all of how that'll work, fantastic, but all I'm really asking at this point is how to get hold of the data in those multi-select fields. The rest is for context etc.
The .Value property of a multi-select field, either a recordset or a control, is defined as a variant array in Access. This means you need to use array functions to get the value.
You can read the value like this:
rs.Fields("MyMultiValuedField").Value(0) 'First value
Join(rs.Fields("MyMultiValuedField").Value, ", ") 'Concatenated values
And set the value like this:
rs.Fields("MyMultiValuedField").Value = Array("Value1", "Value2")
Note that in a lookup field, the keys are stored, not the values being looked up. And in my experience, MVFs have minimal validation when assigning using VBA, you can even insert values of the wrong type leading to garbage.
Related
In Outlook 2010 I have a UserForm with a ListBox.
This ListBox has 4 columns where I show a list of attachments (the columns "File-Name", "File-Type", "File-Size" and "Target-Directory".
Unfortunately the ListBox is restricted in layout functionality, the user can not adjust the column width at runtime (so I have to specify the width of the columns by design).
Because the file path can be quiet long, I set the width of the last column to 999 Pt.
So my ListBox has a horizontal scrollbar.
I want to have the following layout changes to my ListBox:
Add column headers
Change the alignment of a column to right-aligned
Optional: allow the user to sort the list by any column
Optional: allow the user to sort change the width of any column
Optional: show a grid in the ListBox
For 1. I found some answers that this is very complicated and I should use static labels above the list instead.
This is not possible, because my ListBox can be scrolled horizontally.
Is the ListBox really so restricted or is #1 and #2 possible somehow?
I know that there are foreign components available, but I am not allowed to buy any component.
And my solution should work at my colleagues too, so they would also have to install these components.
I have been experimenting with possible solutions to your problem. I think I have taken the listbox approach as far as it will go so I will share what I have discovered.
I can find nothing on the web to suggest that anyone believes you can have listbox column headers without using property RowSource. To use RowSource, you set it to an Excel range.
I got Outlook to create an Excel workbook and to write some data to it. Unfortunately, I could not find any way of getting an Outlook user form to access an Excel range. The syntax for setting RowSource is:
ListBox1.RowSource = "Emails!A2:D20"
This is not the standard syntax for a range and I have failed to discover any method of extending it to include a workbook name.
Jonah_Hess describes an interesting approach in https://stackoverflow.com/a/43381634/973283. He has two list boxes. One is a one-line listbox that contains the headings and the other contains the data. The two listboxes are set to the same number of columns with the same widths. This gives an attractive appearance but if you scroll the data listbox, the headings listbox does not scroll with it. This is not really any different from placing labels above a single listbox.
I tried putting the headings and the data list boxes in a frame and scrolling the frame but could not get it to work. I have used frames with VB user forms but the functionality is very different so there are no lessons learnt that I could bring to a VBA user form. Perhaps someone more familiar with VBA frames could get this approach to work.
I gave up trying to get a solution in Outlook. An Excel macro can access Outlook data so I tried that approach.
I created a macro-enabled workbook. Within it, I have two forms both of which fill the screen to conceal the worksheet. The first form just says: “Please wait while I load data from Outlook”. I am not clear about the data on your form so I imported selected details from a folder full of junk emails which I wrote to a worksheet. I sized the columns for the list box to match those for the worksheet. The result was:
The text is a little small but I think it is readable. The listbox at the bottom allows me to select emails for different periods. Long ago I had problems with RowSource which meant I could change the values in the range but I could not change the size of the range. I have either managed to avoid that problem today or it was a bug that has been fixed.
You can see that the headings are displayed. The columns are a little wide but I consider them to be a reasonable first approximation. Options to change the widths would be easy to implement.
The changes you ask for:
Add column headers. Done
Change the alignment of a column to right-aligned. Possible but difficult. You would need to pad the text with an appropriate number of leading spaces.
Optional: allow the user to sort the list by any column. The data is in a worksheet so easy.
Optional: allow the user to change the width of any column. I have set the column widths at runtime to show it is possible.
Optional: show a grid in the ListBox. Not possible.
If the above is interesting, I could show you all my code and instruct you on creating the forms so you could duplicate my experiment. Alternately, I could just explain: how I imported the Outlook data to Excel, how I included the column headings and how I set the column widths.
I cannot find anything to suggest that anything better can be achieved with listboxes.
An alternative approach is to use a grid of labels. This can give an attractive appearance and one or more columns could be right-aligned. Using the Controls property of the user form, you can treat the grid as a two-dimensional array. I have used this technique long ago and found it attractive and not particularly difficult.
In order to set the alignment of a specific column to the right, trying the opposite way might help you:
Set TextAlign attribute of the listbox to "3-fmTextAlignRight".
Add spaces at the END of the each data in the column of sourcearray, which you want to align LEFT. The number of added spaces should be so large as to exceed the width of the column in which the data appears. You don't have to mind whether the number fits to the columnwidth (overflown spaces do no harm). You may prefer to use & String(30, " ") instead (30 is just for example) .
If added spaces seem to be wholly ignored (i.e. data appear right-aligned only), further add any single character (such as "_") at the end of the spaces.
This is a cosmetic solution, but works when seeing left-aligned figures is too annoying.
After doing the above, please be careful when selecting from the list (trimming the added spaces, keeping BoundColumn data intact, etc.).
This trick works for both Excel and Outlook (not sure for other applications).
Test result in Outlook VBA (...trailing 50 spaces are added to data in column 1 and 4.)
Hope this helps.
Would really appreciate a solution to the below:
I am looking to have 8 sheets.
Main sheet that has all jobs, these are all currently sorted into the following colours :
Red - live
Green - invoiced/complete
Blue - quoted
Black - enquiry
Grey - dead/ lost
Purple - work in progress
Yellow - Retention
what i would like to do is keep the main sheet and have a sheet for each of the above. when the text becomes red for example i would like it to be transfered to the live sheet and vica versa for the rest. this should be in a macro
can anyone help?
Many thanks,
You say "when the text becomes red " so possibly this is a conditional format?
In any case, what you need to do is to attach code to the main sheet's Calculate event . This code should do the following
look at the activecell's color element that you mean (font, background, conditional formating, etc)
Based on that color, copy the entire row to the appropriate sheet
(Can you assume the sheets already exist?)
You will probably need a Select Case Statement. I would declare a worksheet variable and then SET it to the appropriate sheet in the select
and then
Activecell.entirerow.copy ws.cells(ws.rows.count,1).end(xlup).offset(1,0)
will copy the row to the desired sheet at the bottom of any existing rows.
Have a try and come back with code if you get stuck
EDIT: Sorry I missed the "click a button" part. You can ignore the bit about the sheets calculate event - just attach your code to the button. The only thing to worry about then is that you will need to run through all the used rows of the sheet, since there might be more than one coloured row when you click on the button.
I am new in VBA, and I got a task to find a way to implement the 5 stars review like in Amazon/Ebay with graphical stars itself for an excel table. Is it possible that? or even to combine with other technologies.
All I need are some hits, how to do that, and where to start.
Based on your last comment I would like to merely sketch the basic concept of doing such rating manually. Since I couldn't fit it in a comment box I'll put it here as a conceptual draft of what it might look like (this is not an attempt to be a solution):
(1) Getting a star on a sheet is as simple as that
Sheet1.Shapes.AddShape Type:=msoShape5pointStar, _
Left:=100, Top:=100, Width:=7.2, Height:=7.2
(2) Getting four more stars next to it should be simple enough by adding the width of prior star(s) and some extra space to the Left.
(3) Color your star(s) yellow or white with presets (Office 2010+)
.ShapeStyle = msoShapeStylePreset12
(4) In order to locate the stars on the sheet next to the cell containing the value which should be rated you can use the following methods assuming that the value is in cell A1:
.Left = Sheets(1).Range("A1").Left + Sheets(1).Range("A1").Width
Of course, there is a bit more to it than the above. You will have to determine the range of cells for which you want to create stars. Also, if someone adds a column or changes the width of a column then all stars might get changed and will have to be drawn again. Also, you'll have to make sure that the column B is wide enough to hold all the stars. But that's the basic concept (as I would attempt to do it).
I've been given a spreadsheet with a range of cells, each of which contains a list of numbers.
Each number has been given a font colour, so in one cell you might have two orange numbers, a red one and a green one. I need to treat each colour differently; for example, I can count green and red numbers as they are, but I need to see if each orange number occurs in previous cells in the range before counting it.
The number lists are comma-separated, so getting individual numbers shouldn't be a problem, but how do you retain and work with the colour information?
I'd post code, but frankly I'm not sure where to start.
Thanks in advance!
Solved using this:
http://www.mrexcel.com/forum/excel-questions/656265-excel-visual-basic-applications-count-items-cell-color-font.html
Essentially a loop that uses InStr to find commas in a string (in this case, the contents of a cell), then looks at the colour of the next character after the comma. I've just edited it to say if the ColorIndex = 46, copy the subsequent characters into a space in an array. Then I can look at each item in the array, and compare it with other cells in the range to see if it appears elsewhere.
I have a Word 2007 doc with a lot of tables. Each table has certain cells filled with 2 custom colors. I created a macro which takes for input 3 values to feed the RGB function, creating one of the colors, matches it against each of the colors, and changes the match with a new color.
I used an If statement that compares the color of the filled cell with the color returned by the RGB function, feeding the function with the input given by the user.
If ActiveDocument.Tables(k).Range.Cells(j).Shading.BackgroundPatternColor = RGB(inputRed, inputGreen, inputBlue) Then
'code
end if
As I was looking through the document to see the results, I noticed that a few cells from 3 tables were left with the old color, so apparently the macro could not recognize it.
In Word 2007 I selected the cell that was supposed to have its color changed. I went to Home -> Shading -> More colors -> Custom and saw the 3 values that matched perfectly with the 3 values given as input by the user.
After 30 minutes of staring at the monitor, I thought about going to the doctor to have my eyes examined. :)
Before doing that though, I started to debug the app. on each of the cells that were not changed. Upon examining this line:
ActiveDocument.Tables(k).Range.Cells(j).Shading.BackgroundPatternColor
I saw that it returned -1.
I am thinking -1 is the equivalent of null or nil, meaning that either the cell is not filled, but if so, why can I see the RGB values? Or perhaps the system can't read the RGB values, but who is this system exactly?
Do you have a link where the Shading.BackgroundPatternColor method is well explained?
I don't know about a value of -1, but colours in Word 2007 changed slightly so that the values were no longer necessarily RGB values. I have written extensively on this - please see http://www.wordarticles.com/Articles/Colours/2007.php