How to discard mouse click in TDbGrid.OnColumnMoved - delphi

In a TDbGrid.OnColumnMoved event handler, I adjust some column headings colors.
I also use the grid's OnTitleClicked event to pop-up a (sort column) menu.
Unfortunately, after the user drags a column and OnColumnMoved is finished, the VCL calls OnTitleClicked. This means my sort-order pop-up appears after column dragging.
Is there a way in OnColumnMoved I can clear the mouse event queue so that OnTitleClicked doesn't get called?
This thread has this code, but I don't have a Msg in OnTitleClicked.
while PeekMessage(Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST,
PM_REMOVE or PM_NOYIELD) do;
(If there's no way to do this, it's not big deal. I can set a flag in OnColumnMoved so that OnTitleClick ignores the next call to it.)

As mentioned in comments to the question, you would supply the 'Msg' for PeekMessage yourself (var Msg: TMsg). But discarding the message that triggers OnTitleClickis not possible because it is the same message that fires both events. VCL carries out column moving in response to a WM_LBUTTONUP message if a column has been dragged. Later during the handling of the same message OnTitleClick is called.
IOW, while you can remove messages from the message queue with PeekMessage, the message that triggers OnTitleClick is already dispatched since we are in an OnColumnMoved handler.
Easiest approach looks like setting the flag as you've told.

Related

TVirtualStringTree. How to identify the exact node checked by the user?

My question relates to the issue raised in
TVirtualStringTree. How to check a node and its children with a single confirmation?
If the options for propagation are enabled and the user checks an internal node, the events OnCheck and OnChecking are triggered first for its child nodes. Is there any way that the program could identify the exact node checked by the user, when event handler for OnCheck is being executed? I experimentally ascertained that the handler for OnNodeClick is triggered only after OnCheck.
There is nothing built in, you will need to do it yourself.
The OnChecking event for the clicked node seems to be the first one executed at a checkbox click. So, create a variable, say ClickedNode:PVirtualNode (normally nil). In the OnChecking event check if it is nil and if it is, set it's value to the node of the event. The last event to fire is the OnClick event, in which you reset the ClickedNode to nil. In between, in the OnChecking or OnChecked events, you know that ClickedNode triggered the checking sequence.

Is there an event that fires after the DOM is updated as the result of an observed property?

Is there an event that gets fired after the DOM is updated as the result of an observed property being changed?
Specifically, I need to alter the scrollTop property of a container to show new content as it's added. I have to use a timeout now to wait until the DOM is updated before setting the scrollTop to the new scrollHeight.
Thanks for the question. From my understanding, the changes propagate through the models and DOM asynchronously. It's not clear there is one "ok, literally everything all the way through is done updating" event (I could be wrong).
However, I've used Mutation Observers to know when something in my DOM changes. If you're able to watch a specific place in the DOM for a change (or changes), try Mutation Observers: https://github.com/sethladd/dart-polymer-dart-examples/tree/master/web/mutation_observers
Here is an example:
MutationObserver observer = new MutationObserver(_onMutation);
observer.observe(getShadowRoot('my-element').query('#timestamps'), childList: true, subtree: true);
// Bindings, like repeat, happen asynchronously. To be notified
// when the shadow root's tree is modified, use a MutationObserver.
_onMutation(List<MutationRecord> mutations, MutationObserver observer) {
print('${mutations.length} mutations occurred, the first to ${mutations[0].target}');
}

Ensure changes in a data aware control get captured on form close

I've noticed that if a form with data aware controls is closed from the title bar and the active control has had its data changed that change never makes it into the underlying data source. I've traced this to the CM_EXIT message never getting fired for the control.
How can I ensure that no matter which control last had focus these changes get pushed to the data source?
You could send the needed CM_Exit in the OnCloseQuery event of your form.
procedure TMyForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if Assigned(ActiveControl) then
SendMessage(ActiveControl.Handle, CM_EXIT,0,0);
end;
I usually handle this by testing all data set components. If they're in the Modified state, then I simply call Post on them.
You can do this in the OnCloseQuery for the form.
On your OnClose event handler just add the line below:
Perform(WM_NEXTDLGCTL, 0, 0);
It will make the focus go to the next component in the TabOrder and, by removing the focus from the current component, will send the value to the field.
Just FYI. A cross platform way of forcing the control to exit is:
SelectNext(ActiveControl, True, True);
This will work for any control that has at lease one other sibling in the same parent container.
I think the right way is to call UpdateRecord on the underlying dataset components (e.g. in OnCloseQuery). This will update the data from the controls.
If you call Post instead, this will internally call UpdateRecord as well. This is why Marcus' answer will work too.

Is there an event to watch for on pushObject?

I'm programmatically pushing an object (using pushObject) into a list that is sortable. My problem becomes that if I try $(selector).sortable('refresh') or $(selector).sortable('serialize') the serialize doesn't contain the recently added dom item. I can console.log($(selector)) and it seems to know that the dom item has been added though.
My original thought is there an event to watch for once pushObject has finished? Or a callback?
Is there an event to watch for on pushObject?
Easiest way to do this is add an observer that fires when the list length has changed. But probably that's not gonna be enough in this case.
It sounds like this is a timing issue. If you try to call refresh right after pushObject (or even in an observer) the refresh code is going to run before the dom has been updated.
The trick is to make sure you are calling $(selector).sortable('refresh') after the new elements have been written to the dom. That could be from a didInsertElement hook on the dom item's view or from an observer, but as #Luke reminded me in comments best way to do it is by scheduling refresh to run after render has completed. Something like:
Em.run.schedule('afterRender', this, this.refreshSortable)

Which event is fired before current record changes in ADOQuery and how NOT to change the current record?

In my application, there are these data components linked like so:
DBGrid > (DataSource > ADOQuery > ADOConnection)
DBNavigator > (DataSource > ADOQuery > ADOConnection)
Whenever the user selects a different row from the DBGrid, or uses the DBNavigator, the ADOQuery's current record changes. Fine, but when the user makes some changes to the current record, then navigating away from it, the changes made are lost.
I would like to display a confirmation dialogue where the user would need to confirm navigating away from the current record in case there were any changes made. And, when the user clicks 'No' then I would like the application NOT to change the current record.
Where should I insert the code? Which event is it that is fired before user navigates away from the current record and how do I stop the action from continuing?
if anythingChanged then
if messageDlg(...)=mrNo then
ADOQuery.dontChangeCurrentRecord;
Put a conditional Abort on 'BeforeScroll';
procedure TForm1.ADOQuery1BeforeScroll(DataSet: TDataSet);
begin
if TAdoQuery(DataSet).Modified then //if anythingChanged then
Abort;
end;
Strange. What sort of grid are you using that doesn't automatically call Post in this situation?
If you want to do something like this, probably the best place to put the event handler, if the grid doesn't provide a convenient event for it, is on the dataset's BeforeScroll event. To keep the changes from being applied, you can call Abort.

Resources