Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Multi line grid field condition 2

Status
Not open for further replies.

Phil Thoms

Programmer
Oct 31, 2005
245
GB
Hello,
I have a multi line grid that I created in VFP6 (YES a multi line grid) it works superbly and is accessed on a daily basis with new data.
However, I wish to place a condition on a table field called quantity. When the quantity field is greater than 1 then I would like it to display in red.
I know this is straight forward in a normal grid with dynamic properties but I can't manage to achieve it in my multi grid.
For your information:-
I have constructed the multi line grid with several text fields inside a container with control sources from a table, the container has then been bound to a column within the grid.

Your help would be gratefully received.

Thanks.
 
Good to see that you have succeeded in creating a multi-line grid. I use one in many of my applications, and have found them very useful.

You are right that the DynamicXXX properties won't work. Instead, you need to write code in the grid's BackStyle_Assign method. That method fires for each separate row in the grid. Your code can simply test the current record for the relevant condition, and then set the column's font, font style, fore colour, back colour, etc. accordingly.

If you are not sure how to create a BackStyle_Assign method, come back and I will explain it.

[highlight #EDD400]Edit: My mistake. It's the container's BackStyle_Assign you need to use, not the grid's.[/highlight]

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Here's an example of some code from my own multi-line grid class. This code changes the background colour of alternating rows. That's probably not what you want to achieve, but it will give you an idea of the general technique.

Code:
* This code is in the container's BackStyle_Assign method.

IF RECCOUNT() > 5
  * Only do this if there are more than five rows present
  this.parent.BackColor = ;
    IIF(RECNO() % 2 = 0, this.parent.BackColor, this.parent.parent.nAltRowColour)
      && nAltRowColour is a property of the grid that contains the
      && alternating colour.
ENDIF 

RETURN THIS.BackStyle

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Actually the backstyle_access method, I think, and it's famous for dynamically setting pictures of image controls.

Well, with a textbox in a container in a grid column you have its own events again, mostly I'd think about textbox.programmaticchange and textbox.interactivechange. Both these can set the textbox to a certain backcolor or forecolor depending on the value (this.value) state during these events. Design a textbox class, which has a new method Change() and let both of the native programmatic/interactivehange methods call this new single Change() method, then it's easier to maintain what's done in just one single method.

InteractiveChange covers changes due to user interaction, data modification or new data entry, which should also reflect in color changes, for sure. ProgrammaticChange covers any code changing the controls value, including the change of values due to controlsource, so you react to any change and you get the colors initialised by the values coming from the database.

It's just important you set sparse=.f. to not let the active container influence the look of all grid rows. That should be the case anyway, otherwise all other rows wouldn't show the container at all but one single cell.

Bye, Olaf.
 
Olaf said:
you get the colors initialised by the values coming from the database.

Olaf, are you saying that, by using the textbox's ProgrammaticChange, you can have the grid show the desired colours (or fonts, or whatever) at the point at which it is initialised? In other words, does ProgrammaticChange fire at Init time, even before any changes have been made to the data?

I would be slightly surprised if it's true, although I admit I haven't tried it yet.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thanks Mike and Olaf,
I'll try what you've suggested and get back to you asap. In the middle of the Friday rush.


 
Hello Mike,

you're right, the ProgrammaticChange only runs once, not per row. BackStyle_Access works this way:

Code:
Rand(-1)
Close Tables All
Close Databases All

Create Cursor crsValues (cValue C(254))
Select 0
Open Database _samples+"northwind\northwind.dbc"
Use customers

Public oForm
oForm = CreateObject("myform")
oForm.Show()

Define Class myForm as Form
   Add Object Grid1 as myGrid
EndDefine 

Define Class myGrid as Grid
    Procedure Init()
       This.ColumnCount = 1
       This.Column1.AddObject("Container1","myContainer")
       This.Column1.Container1.Visible = .T.
       This.Column1.CurrentControl = "Container1"
       This.Column1.Container1.Text1.ControlSource = "customers.customerID"
       This.Column1.Sparse = .F.

       This.Column1.Width = This.Width
       This.RowHeight = 42
    EndProc 
EndDefine 

Define Class myContainer as Container
    Add Object Text1 as myTextbox
    
    Procedure Init()
       This.Text1.Visible = .T.
    EndProc
    
    Procedure BackStyle_Access()
        This.Text1.Change()
        
        Return This.BackStyle 
    EndProc 
EndDefine 

Define Class myTextbox as TextBox
   Procedure ProgrammaticChange()
      This.Change()
   Endproc

   Procedure InteractiveChange()
      This.Change()
   EndProc
   
   Procedure Change()
      * obviously here make the color depend on this.value or tablename.fieldname
      This.BackColor = Rgb(Rand()*128+127,Rand()*128+127,Rand()*128+127)
   Endproc
EndDefine

If you comment the line [tt]This.Text1.Change()[/tt] in BackStyle_Access you only get one color for all textboxes in all rows. Anyway, this wiring of events makes the color change with any value change, not only during grid paint/refresh/scroll events.

Bye, Olaf.



 
Mike,
As you stated I am asking you because I'm not sure how to create a BackStyle_Assign method. Should it not relate to fore instead of back?
I want the field amount to show in red not the row color. Perhaps I'm confusing things. Don't forget I'm using VFP6.

Thanks



 
Yes, it can be confusing, I agree.

My point is that you need to write code in the BackStyle_Assign method, even though you are not aiming to change the backstyle property. For reasons that I won't go into, BackStyle_Assign fires whenever the form is repainted, and it fires separately for each row in the grid (that's a bit of an over-simplification, but never mind).

What's important is that you can use the code in BackStyle_Assign to change any aspect of the container, whether that be the fore or back colour, the font name, the font size, or just about anything else.

You create BackStyle_Assign at the class level. Remember, this is a method of the container, so you will need a custom container class. It is this class that you drop into a column of the grid in order to create your multi-line grid.

Assuming you have a suitable container class, proceed as follows:

1. Open the class in the class designer.

2. From the Class menu, select Edit Property/Method.

3. In the resulting list of properties, select BackStyle, then tick the box labelled Assign Method.

4. Click Apply. Close the dialogue.

5. A method named backstyle_assign (all in lower case) will now appear along with all your other methods for the class. For example, it will appear in the Methods tab of the Properties window (because it is all in lower-case, it will appear at the very end of the list of methods).

6. When you open the method for editing, you will see this code already in place:

Code:
LPARAMETERS vNewVal
*To do: Modify this routine for the Assign method
THIS.BackStyle = m.vNewVal

You need to retain that code (although you can remove the To-do comment), but you also need to incorporate your own code to actually change the properties of the container. For example, suppose your grid contains sales invoices, and you want to show invoices that are overdue with a thick red border, you might do this:

Code:
LPARAMETERS vNewVal

IF Invoices.DueDate < DATE()
  THIS.BorderColor = 255
  THIS.BorderWidth = 2
ELSE
 THIS.BorderWidth = 0
ENDIF

THIS.BackStyle = m.vNewVal

You see, even though it is the Backstyle's Assign method that you are editing, your code is only concerned with the border colour and width - nothing to do with the Backstyle itself.

By the way, Access and Assign methods were introduced in VFP 6.0, so all this should work fine.

Once you've got this working, you might want to read more about Access and Assign methods, as they open the door to lots of possibilities. I wrote a long article about them in FoxPro Advisor, but unfortunately I no longer have an electronic copy I can give you. Doug Hennig also wrote a paper about them, which you should be able to search for.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thanks Mike,
I'll try what you have detailed and get back asap.

 
Again, it's the access, not the assign method. The grid reads the backstyle while drawing rows.

You're making use of that in doing anything else you want in this method, which becomes an event for you when you simply define the method. What Mike explained is correct, expect you tick Assign Method. If you code in prg as in my example you simply write a method of that name and I think the dialog is also just doing this for you, including writing some base code.

The only thing you need to end in some Access method is returning the value of the property. Every other code before that may do anything like coloring elements.

Bye, Olaf.
 
My mistake.

Philtoms, everything I said was correct, but instead of BackStyle_Assign, read BackStyle_Access. Thanks to Olaf for pointing that out.

The code that is built into Backsyle_Access is as follows:

Code:
*To do: Modify this routine for the Access method
RETURN THIS.BackStyle

Providing you keep that line (you don't need to keep the comment, of course), then the code I showed you should still work. In other words:

Code:
* BackStyle_Access method

IF Invoices.DueDate < DATE()
  THIS.BorderColor = 255
  THIS.BorderWidth = 2
ELSE
 THIS.BorderWidth = 0
ENDIF

RETURN THIS.BackStyle

It's been a few years since I created my own multi-line grid class, which is my excuse for mixing up the Access and Assign methods. Apologies for that.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thanks Olaf.

Mike,
In your step 1 you say 'Open the class in the class designer'.

The container was built in a form and NOT defined as a class. Once I was happy with the container construct it was then bound to a grid column.
No class was involved as such.
Do I need to start again from scratch and build as a class? or is there a way round this?

Thanks.

 
No, you don't need to start from scratch.

Proceed as follows (make sure you have backups of your forms, etc before you start):

1. Open in the form designer a form containing your grid.

2. Select the container within the grid.

3. From the File menu, choose Save As Class.

4. In the Save As Class dialogue, choose "selected controls"; enter a name for your class, and the name of the class library (VCX) where you want to store it.

5. Close the form designer. Open the class in the class designer. Check that it looks OK (it should have all the same properties and methods, and the same controls, as the original container).

6. Go back to the form designer. Delete the container from the grid. Drop the new class in its place.

If the multi-level grid is itself a class, then skip step 6. Instead, open that class in the class designer, delete the existing container, and drop in the original.

If all this is new to you, it would be worth your spending some time getting to know about classes. Doing so could bring lots of benefits to your work.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
Many thanks for latest reply.
I have 3 very different multi line grids so I saw no need to define them as classes. I haven't done very much regarding classes as I've achieved most things through building standard or near standard forms.

However I can see the advantage of producing classes so I'll do as you suggest.

Thanks again.
 
Mike,
I've done everything you stated.
However I can't seem to drag and drop the new class into the grid OR copy/paste. Is there a special way of doing this?

Thanks
 
Well, the first thing to check is: are you sure you haven't already done that?

When you drop a control into the column of the grid, it doesn't immediately replace whatever control was there before. It's possible that the previous container is still there, and is in front of your new container. You can check that by looking in the drop-down list at the top of the properties window. If you can see both the old container and your new class there, then select the old container, go back to the form (click on the form's title bar, not on the form itself - otherwise you risk selecting a different control). Then hit the Del key.

If you can't see your new class in that drop-down list, select the column (in the same list). Then drag your new class (from the project manager) and drop it on the column. If it's not immediately visible, check that the previous container is not in front of it, as described above.

If you have difficulties with any of the above, take a look at this article: Understanding the Visual FoxPro grid control - especially the section headed "Adding different controls to the grid". It explains it better than I can. You might also want to check what the article says about the Sparse property.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
Thanks for your effort.
Whatever I try nothing happens.
Binding a 2 line container with text to a grid column is easy but getting a container class to drop into the grid column seems impossible.
Frustrating to say the least. Is there a way of adding the method in a container that hasn't been defined as a class?

Don't waste too much time Mike as I'll try to work round it.

Many thanks.
 
I'm sorry you are having so much trouble with this, Philthoms, especially as you are so close to a solution.

Adding a container based on your class should be the same as adding a native container. I've no idea why that isn't working for you.

No, there is no way of adding a method to an object that is not a class.

You could try adding the container class programmatically. The article I referenced includes instructions for doing that.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
Thanks for all your help.
I will try the programmatic approach as suggested. I'll let you know what happens.

PT

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top