Is there a better multi-select than the default TDBGrid in Delphi? - delphi

First off, this applies to Delphi 5 Enterprise, as this is what we use at work. There's no view to upgrading any time soon, as this version "does what we need", apparently.
After setting the dgRowSelect and dgMultiSelect options on a TDBGrid, the behavior does not confirm to a standard Windows UI.
I don't think we've ever needed this option before, else I would have noticed how poor the default implementation is on Delphi's TDBGrid. I want Ctrl-Click for single rows (which works OK; not great, but OK) but also Shift-Click for a range selection (which doesn't work).
I suspect I could trap the WM_LBUTTONDOWN message and process it manually in a subclass, but are there any pitfalls that await me down that path?
I'm hoping someone has already had to go through these motions, as I can't imagine people being happy with the poor default effort offered.

The Infopower library, available from Woll2Woll [http://www.woll2woll.com], contains an extended datagrid which includes properties (msoAutoUnselect,msoShiftSelect) that will provide the behavior you want.
These properties were introduced very early in Infopower's history, so even the cheapest version you can find should be adequate. Infopower costs less than three hundred dollars in any case.
I am not affiliated with Woll2Woll in any way; I just use their product.
-Al.

Related

sometimes CxGrid column looses RepositoryItem property

I am using delphi xe2 (fully updated) and Express QuantumGridSuite 13.2.2 . I've much columns on grid and i set RepositoryItem for some columns. EditREpository component is on another form. Some times that columns repositoryItem property is clearing randomly. I think that something is triggering that but i couldn't found what is this about and how is that do?
Tnks for your helps.
This problem of component values becoming "lost" at design time is a known phenomenon, even with EMBA's own components. Usually, it manifests itself when forms are first opened in the IDE.
In my experience, ymmv, it nearly always happens with a property of some component of form A which references a component on form B, and it seems to happen more frequently if form A is opened in the IDE before form B.
Anyway, there are things you can do to try and identify the problem and at least one work-around you can use until you do. But, before you start, the very first thing to do, if you haven't already, is to ask Devex whether they know about the problem. No disrespect to the readership here but they are more likely to know, and it may turn out that you've missed a maintenance update that fixed it.
When I've had it happen with components I've written myself, usually it has been caused by some error in my coding of the component's initialization and/or property setters. In my own components' cases, I've always been lucky in that although at first the behaviour seems random, in fact there has turned to be a specific sequence of actions in the IDE that triggers it. If you can identify a reproducible sequence of actions, you're 90% of the way to getting the problem fixed.
The best place to start is to make a reference back-up of your code in its pre-problem state. Then try out various sequences of actions in the IDE, rolling back to your reference in between, until you find one that provokes the problem. If this sounds tedious, it is, but you may get lucky and spot a pattern early on. If you don't, then keep reminding yourself that the problem only seems random because you haven't spotted the pattern yet.
However, I have the impression (though no proof) that another misbehaving component can disturb the setting of the properties of the component which is losing the value. So, one thing to look at is what other components are on the same form as your affected one. Not all have the same pedigree as the Quantum Grid and its siblings from Devex.
Things I've found effective to isolate the problem with components I've written myself are:
Removing all the other components from the form.
Seeing if I can find reproducible sequences of actions (e.g. what order forms are opened in) that trigger the problem.
Editing the DFM so that the affected component appears last in it. Ditto, first.
Running the IDE in another instance of itself. The main initial reason to do this see if you, or rather the debugger, can unmask a normally-silent exception occurring in some design-time component code that may be involved on the loss of the property value.
Devex's Quantum Grid is widely used (I do myself), has a long lineage and their code is usually top quality. Although I don't imagine it's perfect, I would start by assuming that the problem is caused by something else.
As you may have noticed, one of the most troublesome things about this problem is that if the component is on a rarely-used form, often the first you hear of it is when a user reports it.
Anyway, with all that said, if you can come up with a reproducible test case involving only Devex components and the standard ones, that can be submitted to them for investigation, I'm sure it won't take them long to find and fix the problem. And I'm sure they will fix it if it's in their own code (I wish the same were true of EMBA themselves).
However, without a reproducible test case, I think the best you can hope to do is to add explicit code to your form's creation to set the component value at run-time, e.g. when the form is first created. With my own problem components, once or twice I've found that careful tracing into the code I've added to do this has led me to the cause of the problem.

Which TDataSet, TDbGrid events to use for implementing an Un-Do feature

I'm planning to write an un-do feature for use in a TDBGrid hooked up to a TTable (BDE). I want it to work at the grid cell level.
I'd like some suggestions on a good way to implement this.
I plan to keep a list of records that changed, the field name, and their former values.
What I need, I believe, are an OnEnter and OnExit for cells.
TDataSet.BeforeEdit is half of what I need, I think. But, TDataSet.AfterEdit is a bit misnamed -- it's called not after the edit is completed, but "after the TDataSet enters the edit mode" (to quote the help system.)
TField.OnChange would work though... I think ...
My thinking is that AfterEdit will grab the contents of the cell. And TField.OnChange will log the change to a stack I keep. (Thank goodness for Delphi's Generics. I never knew what I was missing before we had them!)
Any suggestions on how my thinking, caveats, or better ways to do this?
PS Standard mea culpa: Yes, yes: the BDE is deprecated, I shouldn't be using it, yada, yada, yada. Tell that to my boss who has me maintaining 1.5 million lines of legacy code. Yes, yes: someday the BDE will go away and we should be proactive and make the move now. We know. Thank you.
As per Robert's request, my comment(s) rewritten as an asnwer.
Don't cells already support undo by typing Ctrl-Z or Esc?
Or if you want to keep a stack of edits to multiple cells and have "undo" revert them one by one then you could combine dataset and field events. The dataset OnBeforeEdit will give you the base for all cells, each field's onchange will give you its OnAfterEdit which would render the same value as an (imaginary) Field.OnBeforeEdit when the user comes back to edit the same cell again.
If to implement Undo / Redo functionality for BDE datasets, then best will be to inherit your own datasets, and there override some methods, instead of to hook events. Then replace all TQuery with TYourQuery.
More simple is to use TClientDataSet + TDataSetProvider in the places where Undo / Redo is needed. Set TClientDataSet.LogChanges to True. To Undo editing call UndoLastChange. Sorry, you cannot Redo, although.
Migration from BDE to some 3d party data access components may be simple and straightforward. Eg, AnyDAC has API compatible with BDE, well documented migration procedure, tool for automating migration. Also, after migration you will get (2) right out of the box.

Replacing non-visual components with code

Is "Replacing non-visual components with code" a proven optimization technique in Delphi 7. Mainly with respect to Database Access.
The Web site you cite talks about replacing a dialog-box component with code that would display the dialog box without the use of any component. The alternative is to write a couple of lines of code to set up and display a dialog box whenever you need one, and to skip the component altogether. It's not really an optimization in speed or size, though. It's not a speed optimization since your code would do exactly what a component would have done anyway, and it's not a size optimization because the space any one component occupies in a program is negligible.
Database components aren't so easily replaceable as dialog-box components. Nearly everything in Delphi is designed to use descendants of the standard database components. If you don't use the components, then you won't be using any of Delphi's database capabilities at all. You can use the database libraries' native APIs if you wish, but I think that would be foolish if your goal is really optimization and you haven't identified the components as the source of your program's non-optimal behavior. Consider how much time and effort it would take you to rewrite your program without the database components.
I don't see how a form-based dataset/query/table/etc., would be faster or slower than one created in code. However, I like to put them in code as it's easier to maintain. I've seen screens with SQL embedded in a component, and then it's overridden in the code. Then I have to stop and investigate to determine which SQL is actually in effect. Sometimes the SQL in the form is good, sometimes it's used for a while and then trumped by the code, sometimes it's never active and the SQL is trumped in the formcreate. So I have to determine whether this is by design, or just sloppy leftovers. Also, it's easy to miss SQL changes in code reviews if they're in the .DFM and not the .PAS. i.e. I don't always look at the .DFM because I'm not interested in whether a label caption changed or a button moved.
So while it's nice for prototyping, when it comes to production code, you're better off having all of your database logic (SQL, table and field definitions) in the .pas file.
Update: I have finally given CnPack a try. Among the dozens of goodies, is a brilliant tool called "convert selected components to code". Form Design Wizard | More... | Convert Selected Components To Code. It does it all for you.
This is not a matter of being a component or not a component. If it comes to database access then BDE is extremely slow so changing it for sth else is a good move.
By the way - optimization is not about 'proven techniques' - it's about identifying a problem and solving it. If the problem happens to be slow db access then this is what you have to change.
Generally no. There is no additional overhead in using a non-visual component. It is created very quickly and works at runtime exactly at the same speed as one "created in code".

Reading Excel spreadsheets with Delphi

I need to read from and write to Excel spreadsheets using Delphi 2010. Nothing fancy. Just reading and writing values from specific cells and ranges on different sheets. Needs to work without having Excel installed and support Excel 2007.
Some things I've looked at:
I've tried using ADO, which works OK for selecting everything in an entire sheet, but I haven't had much luck reading specific cells or ranges.
NativeExcel looked promising, but it doesn't seem to be in active development, and they don't respond to e-mails.
Axolot has a couple of products. The main product seems to be very functional, but is pricey. They have a lite version, but it doesn't support Delphi 2010.
Any recommendations? Free would be great, but I'm open to a commercial solution as long as it's reliable and well supported.
TMS Flexcel - I know it looks like a reporting component for Excel (which it does very well and is a very handy tool to have in your toolkit) but it also includes components for reading and displaying Excel files. I've been very impressed with how well Adrian Gallero seems to know the Excel API, including Excel 2007.
http://www.tmssoftware.com/site/flexcel.asp
Not free of course, but at 75 Euros I think it's good value.
I've had very good luck with ADO, provided the Excel sheet is a fairly straight-forward row/column layout.
The key with using ADO, I've found, is treating the Excel sheet like a database. If your Excel sheets are primarily straight row and column layouts, just treat the rows as database records and the columns as fields. Navigate to the desired row first by searching for a particular column (field) value (preferably something unique), and then read the desired cell in that row by referencing the field that is the column name.
If your Excel sheets are more free-form, then it will be more difficult.
Don't write off NativeExcel. I have used it for a couple of years now with excellent results. It's fast and versatile. I use it to produce a nicely formatted multi-page spreadsheet with frozen panes, formulas in cells, and data from a client's database for them to use for input and then send back to me. My clients were really thrilled when they got the first spreadsheet from me because it reduced their workload tremendously and it was fairly intuitive for them to use.
I don't know why they have not responded to you because I have updated their package at least a couple of time over the last two years. When my license expires, I definitely intend to renew.
I'd recommend SMImport / SMExport from http://www.scalabium.com
Mike has always been really helpful and quick to respond.
What really helps is if you have some kind of control over the layout of the excel file.
I have built a whole unit and acceptance testing framework where the data and the test controls are all contained within an Excel spreadsheet.
I did everything through ADO. You can restrict your ADO SQL query to a whole sheet, a named range or any range for the matter. In my opinion and experience, this method is very powerful.
Two things that did cause me some problems :
1. depending on how your sheets are named, ADO might or might not see them (again, if you have control over the layout, great !)
2. be careful about the data type ADO returns when you read data i.e. it might show numbers as strings. This is because ADO tries, IIRC, to guess the data type based on the first few rows.
Disclaimer : I have never used any of the tools mentioned above. ADO did the trick for me, and I feel more in control since I wrote the code for my framework (save the ADO part obviously...).
Bruce, I've used the Axolot XLSReadWriteII component for going on 10 years now. It's been very good, and their support forums (while lite on content) seem to be monitored pretty well. The XLSReadWriteII2 version is blindingly fast, and supports all sorts of things like charts and graphics, named ranges, adding formulas on the fly, cell formatting (including borders and shading, merging cells, vertical and horizontal alignment, auto-width column sizing, and so forth).
I haven't upgraded to the latest version (we're still using XLSReadWriteII2) because we can still use the Excel XP format files, and I haven't used the XLSMini at all. I can say really good things about the full product, though; in fact, I just used it for a couple of database export things this past week.
If you decide to go that route, I have a bunch of notes about how to do different things that might be useful; if you want them, drop me a note. I also have a Delphi 2007 app that just shows how to do different formatting and alignments; I actually reproduced an existing, fairly complex report in Excel complete with all of the formats, borders, etc. that I'd be glad to let you have as well.
DISCLAIMER: I have no connection with Axolot or any of their employees. I'm just a very happy customer who learned of the product at a previous job, and was impressed enough to buy it when I started my current one.
Don't bother with Axolot's XLSMini (lite) version. I haven't purchased either of them yet, but I asked about Excel 2007 support in early 2008 and Lars told me XLSMini was based on the XLSReadWriteII and that both would be updated with Excel 2007 support at the same time. XLSReadWriteII has had Excel 2007 support since April 2008; XLSMini still doesn't have it.
With great luck, I've used Axolot for some years now. The support forum isn't exactly brimming with messages, but maybe that's because it works so well?
You can use ADO connection string like
http://www.connectionstrings.com/excel
than include the options (in the third tab of ado connection string):
Extended Properties=Excel 8.0;HDR=Yes;IMEX=0
for security purposes Microsoft prevent modifications (with IMEX=1)
http://support.microsoft.com/kb/904953/en
Sample SQL (don't forget the brackets):
SELECT * FROM [Sheet1$]
The only thing you can't do, is deletion:
http://support.microsoft.com/kb/257819/en
So to delete a row make it empty!
You can also use SQL via ADO to export:
YourADOConnection.Execute('SELECT * INTO aSheet IN "'+ExtractFilePath(ParamStr(0))+'Exported.xls" "Excel 8.0;" FROM YourTable');
I would advise to go for an option where you don't need Excel installed on the machine. I once used a component that could easily fill in some data in one sheet without needing excel installed. I would also do most of the Excel work in the Excel sheet itself. And just use the components to fill in some data on the sheet.
My 2cts.

Edit status(and other fields) in fogbugz list view

We're evaluating the 45 demo of fogbugz. Thus far I like it, but there are some obvious things I'm missing.
What boggles me the most is how I can easely alter fields in the list view. I would like to open the detail screen as little as possible. It seems to be possible with the estimation column, why isn't it possible with all the other fields (like project, priority, status etc.?).
What you are asking for can not be done in FogBugz 6. You have to open up the case in order to edit most of the fields. Why they made exceptions for time estimates, I don't know.
The rationale here was as a feature to accompany quick case entry. (That's the "Add Case" link at the bottom of each group or at the bottom of the grid.)
The thinking was that it'd be neat to be able to add cases quickly and then burn through the list, estimating them quickly. We didn't really expand our thinking to include moving cases around or changing things like releases/milestones, etc.
This is something we'd like to offer in the future for many more fields, and one of those weird situations where adding a small, specific feature can sometimes make the fact that the larger, general implementation of that feature isn't there yet.
FogBugz 6 isn't big on customisation. You can edit the categories and statuses in the database tables directly (though you need to edit the "internal" project and click OK for the cache to be refreshed.
FogBugz 7 is coming out this year hopefully, and may well address many of these issues.

Resources