I have a PageControl with seven TabSheets and all Tabs are hidden and I change pages using pcMain.ActivePage:=tsAuto (tsMarine etc.) It works, but the Change and Changing events do not get fired.
I tried the following, but it only works when Tabs are visible.
http://delphi.about.com/od/adptips2005/a/bltip0205_5.htm
I also wrote a procedure using pcMain.SelectNextPage(True) incrementing and decrementing a counter and the SelectNextPage but it also only works when Tabs are visible.
Anyone have a suggestion how to get around this issue? I need to use the AllowChange of the Changing-Event to prevent leaving a page if a Database is in an Edit-state.
The code from About.com should work fine. It explicitly calls CanChange and Change, which in turn call the event handlers, if any are assigned. They do not check whether the requested tab is visible.
Furthermore, SelectNextPage should also work. You just have to make sure you pass False for the second parameter to tell it to disregard tab visibility. (If you don't specify a value for the second parameter, the default value is True.)
If neither technique works, then you need to dig deeper because the problem is elsewhere.
One other thing you can try is to simply not assign a new active page if there are pending database changes. You're the one deciding to go the next page, after all. If you know in advance that it shouldn't happen, then don't attempt it in the first place.
Related
This is a strange one: This is the situation
The application builds an edit form at run-time from an XML document. The UI/UX design is such that there are three levels of nested TTabControls and for the final (lowest) level the TTabItem is created at run-time. This has a TVertScrollBox which itself contains a column-grid control of mine and that (at last!) contains the THtmlEditor.
The problem is that when the controls are built and the content loaded, the THtmlEdit initially ignores keydown. It will respond to mouse events, the caret can be positioned. Switching to a different top-level tab, or away from the whole application and back, then cures the issue and the editor responds to keydown messages.
I have tried putting a breakpoint in procedure THtmlEditor.KeyDown() ... and then tracing back up the call-chain. There doesn't seem to be anything behaving differently. I've paid particular attention to input focus, explicitly calling Editor.SetFocus even though that is apparently already called ...
I have tried putting a conditional breakpoint in function TPlatformWin.HandleMessage: Boolean; ... and my only observation is that when in non-working mode, the call to DispatchMessage(Msg) doesn't arrive at the editor, or its parent form.
I have tried to build a MDC for this, replicating the structure outlined above but ... that always works!
What can I try next?
Has anyone seen this behaviour (and fixed it)?
EDIT:
The detail I didn't mention -- didn't think about it -- is that for the error condition to show, the control focused before the THmtlEditor is a TWebBrowser. If I set focus on a TEdit after TWebBrowser and then to THtmlEditor it seems to work.
Grrr!
This is only half an answer, but for future reference, this is what I've done:
It's a bodge :-(
I've put a TEdit on the main form and set it invisible. I've then added a handler to the MainForm OnFocusChanged which sets a boolean trap-flag to track if TWebBrowser has previously been focused.
For the instances of THtmlEditor I've added an OnClick handler which checks the trap-flag and makes the TEdit visible, calls SetFocus on it, re-hide the TEdit and return True so that the THtmlEditor can re-set focus to itself. The trap-flag is to avoid unnecessarily losing focus if the user is just clicking in the THtmlEditor.
The next step -- which I may never get to -- would be to trace through the focus code for TEdit. My suspicion is that it all relates ITextInput which TEdit supports and THtmlEditor doesn't.
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?
I have two Meteor.Collections in my app. One contains a bunch of "slider" objects, which define a title, max, min, base value, and step for each slider. Now, I have two problems. The first is making the sliders show up in the first place. I've tried to put the following code:
Sliders.find().forEach(function(slider) {
$("#"+slider._id).slider({
min:slider.min,
max:slider.max,
value:slider.base,
step:slider.step,
change:function(event,ui) {
Data.update({_id:Data.findOne({slider:event.target.id})._id}, {$set:{value:ui.value}});
}
});
});
in Meteor.startup, at the end of my client.js file, in a $(document).ready() block, and nothing seems to get it to work. When I paste it into the javascript console, however, it works. Anyways, that's my first problem.
My second problem is that whenever I slide the slider, the slider disappears. I can keep dragging the mouse around to change the value, but once I let go of the clicker, I can't change the value anymore. I've tried using the above way and calling a Meteor.method that changes it on the server side. It's the fact that I'm updating a collection that is published to the same client that makes the slider disappear. Anything short of that doesn't cause it to disappear. How should I deal with this?
Thanks!
Have you already tried using the Template.preserve method? http://docs.meteor.com/#template_preserve
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.
I have a tPageControl on a form, and have made a nice 'welcome page' as a new ttabsheet at design time for the user to start off with. However, if the user closes this tab, I would like the option to bring it back, as it was in originally (much like the welcome page in the Delphi IDE). This seems like a simple problem...
When the tab closes, the original sheet is freed and set nil. I tried creating the sheet again by name (e.g. tabsheet1 := ttabsheet.create) and assigning it to the pagecontrol, but none of the original components from the sheet are there anymore...
I know designing the welcome page as a separate form, creating it when I need it and slapping it into a new tabsheet would work... but I was just wondering if there was a way to do it with the design time tabsheet.
Thanks all!
Rusty
As Serg mentioned, you can just set the tabsheet's TabVisible property to false when you want to hide the page. The page control will switch to the next tab if it needs to, the tab will disappear, and the user won't be able to switch back to it until you change TabVisible back.
Re-creating the design-time tab sheet will be quite a challenge because all the information describing its layout is embedded in the DFM resource for your form. It's not like there a separate resource for each tab, so you'd need to read the resource, extract the portion relevant to the tab, and then get ReadComponent to build a new instance; nothing in Delphi is designed to make that very easy, so you should consider other options.
The easiest solution would probably be to design your welcome page on a frame; I've found frames to be a little more cooperative than full-fledged forms when it comes to re-parenting them.
Another option is to create the entire tab in code. GExperts has a tool to make that pretty easy. Select the tab sheet, and then choose DExperts's "components to code" command. That places some code on the clipboard, and you can paste it into a function in your program. The code will contain everything required to re-create the selected components in code instead of building them from the DFM resource. Then, you can use that function to not only re-create the tab after it's been closed, but to create the tab in the first place. That way, you can be assured that you're creating the same thing both times.
The reason your attempt at re-creating the tab didn't work is that the name of the variable used to hold a reference to the form doesn't really define anything. All you did was create a brand new TTabSheet. The fact that you stored a reference to it in the same variable that used to hold a reference to the old tab is irrelevant. (But please feel free to give that variable a more meaningful name; all "TabSheet1" says is that it's the first tab you put on your form, way back when you first started working on this project.)
Rob's right about what's going on, and about using frames to fix it. Bit if you want a simpler solution, you could try just making the tab invisible whan the user closes it, instead of freeing it.
Thank you all for your comments and suggestions. A couple notes :
I tried the GEExperts option (pretty nice, I havent used this one before!) : however, it did not preserve many design time settings (font size and color for example)...also there were components with glyphs that didnt get saved....
Changing the visibility of the tabsheet doesnt seem to work either; the pagecontrol doesn't seem to know what to display, even after calling .Refresh ...it shows whatever is underneath your window.
Anyhow, I might investigate the frames option, but likely will just move the components to a new form and call it when needed...
Thanks again!