I seem to have a mental block with this one.
I need to save recent changes to a Record. I am doing it OK with buttons for "New" "Edit" "Post" "Next" etc but when a user double-clicks a DBGrid, it is now too late to make changes as the DBGrid selection has moved the database cursor to the selected record.
I can't use AutoUpdate as the data that may have been changed is not something the user would have directly entered, it is a value that is changing all the time.
I'll try to describe it better: While the user is reading a Test-page, a timer is counting down or up. When they click the "Next" or "Prior" buttons I can save the timer setting. But, if they Double-Click the DBGrid I have no way of first changing the current Record before the selection moves to the clicked-Record.
I tried using the
Procedure TForm1.tblTestOnBeforeScroll(...
begin
tblTest.Edit;
tblTest.FieldByName('TimerCt').AsInteger:=ClockCtr;
tblTest.Post;
end;
But, that crashed the database, not surprisingly, but I thought I would give it a try before asking here.
How do I deal with the current record? I do not want to disallow the double-click if possible as it seems nice and intuitive for the user.
I'm afraid that what you do on DBGrid is a wrong in concept action.
Key point is DBGrid is a data aware control. So everything you do on it must based on it's datasource then it's dataset.
There is a DblClick event on TDBgrid. But still you have to check it's dataset to see what record is active.
The code you shown above clearly lead you to an endless loop.
When you doing a scroll, the dbgrid will call OnBeforeScroll event, moving the active record
and call OnAfterScroll. Your OnBeforeScroll code does an data update. Then dbgrid abort its operation cause of data change. Then after data update, it try to scroll again, and the data change happen again. Endless loop happen here.
best regard
Apologies in advance if I'm misunderstanding you, but it seems to me that either the premise of your question is wrong or there is something relevant you haven't told us about what you're doing. Please try the following:
If you don't have one already, please temporarily add a DBNavigator to your form and connect it to the same DataSource as your DBGrid. The point of doing this is so that you can more clearly see what's going on.
Then, in your DBGrid's Options, set dgEditing to True.
Finally, comment out or disable your BeforeScroll handler, save and run your program.
Now, click once in some cell in your DBGrid that contains a value which it's ok to change. Click it a second time so that it selects the value in the cell rather than the cell per se.
Make some change to the cell value, but do nothing else for the time being. You should notice that a) the current record indicator of the DBGrid has changed from a black triangle to an I-Beam graphic, like ][ and b) that the tick and cross buttons of the DBNavigator are now enabled.
Now, without doing anything else on the form, click in another row of the DBGrid. You should find that a) the change to what was the current record in step 5 has been saved and b) the current row indicator reverts to the black triangle and the DBNav's tick and cross buttons are disabled.
(If you don't get the behaviour I've just described, create a minimal new project and try that instead, as some other change you've made in your existing project may be interfering with it).
What I've described in 5 & 6 is the default behaviour of a DBGrid and insofar as I understand your q, that seems to be the behaviour you're trying to achieve. If that's not the behaviour you want, please explain exactly how what you do want differs. It's not clear to me where the user double-clicking on the grid comes into your q, except that that action may move the dataset's cursor (if the dbl-click is on a different row than the current one), but as the default DBGrid behaviour will save changes to the current row before it moves the dataset's cursor, it will do what you seem to want automatically.
Btw, what "AutoUpdate" do you mean? Did you mean TDataSource's AutoEdit property?
Related
I am using TMS FireMonkey Grid in my app and currently trying to implement the ability to select a range of rows by double-clicking on the first row and then double-clicking on the last row of the range. I use the SelectRows(StartRow,EndRow) method in the OnCellDblClick event handler. It seems to work, except for one thing: the RowSelectionCount does not get set properly (equals 1, regardless how many rows I select) until I call ShowMessage() with something random, like 'Hi!' - after that it gets set to a correct number of selected rows. I figured it has something to do with focus, so I tried to use the SetFocus to change focus to another component of the form and then back to the grid, but that didn't help. Any ideas on how to get RowSelectionCount to carry a correct value right away?
The grid's SelectionMode property is set to smDisjunctRow - according to an email I received from TMS Support, this setting should allow me to use RowSelectionCount.
Thanks in advance!
I have three DBGrids and three Tables, and two of them are linked with Master Fields and work as expected. When the user clicks on grid-1, it shows three items in grid-2.
When the user clicks on grid-2, I want to use Locate to select the Row in grid-3
Problem is that the grid-2 OnCellClick event is fired before the data has changed to the appropriate Row. e.g.
Grid-2
Flowers <-- this has focus and Dirt has focus in grid-3
Weeds
Trees <-- then I click here
Grid-3
Dirt
Water
Gum <-- and using Locate in the grid-2 OnCellClick I
want it to show Gum but grid two is still
internally on Flowers and stays on Dirt
It seems that the grid does not change to the Row until after the OnCellClick event.
I need an AfterCellClick event.
Can someone please shed some light on how to go about that?
Thanks
You shouldn't be using OnCellClick. Use the TDataSet.OnAfterScroll instead. It's called automatically when the record (row) pointer is moved, after the movement is done. This means that when the grid attached to the second table is clicked and the record pointer is moved from Flowers to Trees, the second table's OnAfterScroll event will be fired after the row changes, and in that event handler you can do the appropriate Locate in the third table.
When creating TDBGrid components dynamically at runtime, i can't forbid user to edit values in cells. This is how I am trying to accomplish this type of behaviour:
TDBGrid *DbGrid = new TDBGrid(Owner);
DbGrid->Options = DbGrid->Options >> dgEditing;
When disabling dgEditing in form designer all is functioning correctly. I can't find the difference between these two cases. What should I do to disable edit of DBGrid cells?
The trick is to do this in following way:
DbGrid->Options = TDBGridOptions(DbGrid->Options) >> dgEditing
but I do not know what is the difference.
I have the same problem with the Seattle version of C++Builder in that I am unable to programmatically change whether the DbGrid allows or disallows editing. The DbGrid->Options values CAN be changed without requiring the TDBGridOptions() cast but the DbGrid does not follow what the DbGrid->Options are set to. If they are set in the object inspector for dgEditing enabled, then the DbGrid always allows editing no matter what the state of DbGrid->Options.dgEditing is and if in the object inspector dgEditing is disabled then the DbGrid never allows editing. It at first APPEARS to work (i.e. the highliting of rows vs cells changes). I have tested this using both DbGrid->Options.ToInt() and DbGrid->Options.Contains(dgEditing) to ensure I'm not stumbling over myself.
I finally found a way to make it work.
If you set the dgEditing to true (for the Options of the DBGrid in the Object Inspector), this will let the user edit at any time. Then, set DBGrid->ReadOnly=false when the user should not be allowed to edit.
I did not have any luck trying to set the individual DBGrid->Columns->Items[ii]->ReadOnly=false. The program did not prevent me from doing that, but it did ignore whatever I had in it.
I wrote a special small test program with minimum components and was able to get good results just by setting the dgEditing to true in the object inspector and then changed dgEditing to false when I wanted to prevent the user from editing, but when I put it into my full program, something prevented the DBGrid from working.
The DBGrid->ReadOnly may be a work-around for someone else also.
I have a TcxGrid which consists of a master TcxGridLevel and 2 child TcxGridLevels (all of which use a TcxGridDBTableView). I would like to hide one of the child levels depending on the value of the master level record values. How do I go about this?
Here is a link to DevExpress describing what you want:
https://www.devexpress.com/Support/Center/Question/Details/Q96738
But this has some disadvantages in my opinion. First it is quite slow with bigger datasets. Second it comes to "flicker" when your master level changes frequently and the grid has to be redrawn. Maybe it is possible to set a filter to your detail-dataset so the details are "empty" when your nmaster has the correct condition. There is a property in TcxGrid to hide empty detail-tabs automatically.
Somewhat out of context but in case the link goes dead again:
1) How can I trigger Level3 OnGetGridView, because Level3 View was not change as I was expected
The OnGetGridView event is raised only once when the detail is first expanded. After the event handler has been executed, the specified GridView’s clone is created and cached so that the event doesn't fire when expanding the same master record next times. If you need the event to be raised later, you can clear all detail clones by calling the master DataController’s ClearDetails method or ClearDetailLinkObject methods.
You can find this information in the "TcxGridLevel.OnGetGridView" topic of the ExpressQuantumGrid's documentation.
2) I am also changing Level2 and Level3 Caption for every Gridview that it showing, but the changing is not automatically, sometime the Detail View need to be close and open again to make the Caption change.
If we're not mistaken, you change the Level's Caption in its OnGetGridView event handler. If so, the new caption isn't applied immediately because painting of the corresponding element isn't completed. As a workaround, you can perform a "delayed" operation by posting a custom message. I've attached a sample project to illustrate this approach in action. Hopefully, it will serve your needs, and adapting it won't be aproblem.
Sure I've seen this done before but off-hand I can't find any examples.
I've got a TListView, set in 'report' viewstyle. It has about half a dozen subitems, and one thing we'd like to do is have the 'hint' (tooltip) on the listview dynamically show another field of data. That is, each time you move the mouse over any given row, the 'hint' would show some text relevant to that particular row.
I'm partway there - I can do this using the OnInfoTip method, but unfortunately once a tip has appeared, Windows seems to decide that I don't need to see a hint for the listview again until I move the mouse away from the listview and then back 'over' it again. Simply moving the mouse down to the next row, all-the-time keeping the mouse over the control, doesn't persuade the program to display the new hint.
Just to be clear - I've got OnInfoTip working so that the program does display the right hint relevant to the item I first moved the mouse over. Changing the hint text isn't the issue. The problem is that moving the mouse to another item in the listview doesn't cause the software to show a new hint. (Hope that makes sense).
Is there some proper way of getting this behaviour to work, or am I going to end up doing something icky with mouseovers and then manually drawing a hintbox (etc)?
check the following link:
Display Custom Hints for TListView Sub Items
Edit:
I just checked it now on delphi7 it's showing the hint for every row dynamically after moving the mouse on the listview.
Offtopic: This is simple in Virtual Treeview component, it is build-in feature.
i was using the OnInfoTip event (i didn't need hints for the subitems). the hint was "flashing" (show/hide/show/hide/show/hide/show/hide). found the listview's ShowHint was false. set it to True and it worked as it should.