Touch and drag does not fire mouse up/down events (Delphi) - delphi

In my application I have used the OnMouseDown and OnMouseUp to create a windows desktop style selection box. OnMouseDown I create a semi transparent blue window and get rid of it in the OnMouseUp.
The result is a nice transparent box to indicate the selection area in a grid control.
The problem is that on a touch screen the mouse down and up events do not get called when you press and drag like you would with a mouse. The up/down events are called if you simply press in one spot but not if you touch and drag.
My current thinking is to use WM_TOUCH messages and capture the touch and drag myself but I am hoping there is a better way or something I have missed. Any suggestions?
(This is a VCL app under XE5)

Related

Changes the cursor when dragging a borderless window

I use the code in Bruce McGee's reply in this post, to drag a borderless window, and it works great.
The problem was that I could not find a way to change the mouse cursor at the start of the drag (and return it at the end of the drag). OnMouseDown and OnMouseUp events seem to go wrong after reading this code in the OnMouseDown event.
How can I do this?

Delphi: How can I check if any mouse buttons are pressed - OUTSIDE of a mouse event?

I have a TDrawGrid and want to handle clicking on a cell and scrolling through cells with the mouse wheel slightly differently: When scrolling with the mouse wheel, the view shall center on the selected cell, when simply clicking on a cell, the view shall not move (because that'd be confusing).
Scrolling with the mouse wheel fires the OnSelectCell event. Clicking on a cell FIRST fires OnSelectCell, followed by OnMouseDown. So I need to figure out if OnSelectCell was triggered by a mouse click. Easiest way to do (that I can think of) would be to check the current mouse-button state.
OnSelectCell doesn't come with any TMouseButton or TShiftState parameter. So how can I query the mouse-button state?
Use GetKeyState passing VK_LBUTTON to identify the primary mouse button. If the return value is negative, the button was down when the system generated the input message that led to the OnSelectCell event being fired.

How to get the control under the mouse cursor in onMouseDown event?

I have a TGridLayout filled with some images in a Firemonkey HD Application. In the gridLayout's onMouseDown event I want to get the image object on which the user has clicked, but I have only mouse coordinates.
Implementing onMouseDown event for every image is not an option, because if an image is removed from the gridlayout an empty space remains. In this case I also want to know if the user has clicked in this empty area.
Is there a some kind of "getChildAtPos" or "FindVCLWindow" analog in Firemonkey?
Thanks!
TForm.ObjectAtPoint should do the trick.
FindVCLWindow does what you need. You need to specify the point at which the control is, in your case it's mouse position.

TStringGrid dirty hack - Restricting the selection to one single row

I have a heavily modified control based on TStringGrid. I want to allow the user to make selections in this grid but restrict the selection one single row (the current row).
Implementation:
When the user presses the left mouse button I am using a dirty hack: On OnMouseDown event I capture the mouse cursor and keep it on the current row. The user can move the mouse device up and down on its pad but the cursor will not go up or down. It will stay on the current row. When the user releases the button (OnMouseUp event), I release the capture.
However, this hack is as I said very dirty. There are several problems. For example, if the user presses the left mouse button (LMB) and then without releasing that button it presses the right button, the associated pop-up menu will pop but the mouse capture will never be released. So, the mouse will be locked in a screen region until the user will has the brilliant idea to click the LMB one more time to unlock the mouse. This may be a bug in D7. There is a separate post about it here: TStringGrid - OnMouseUp is not called!
There is a elegant way to do this?
Edit:
OnSelectCell is not working. OnSelectCell event is called only once when you click the cell. If you keep the button pressed and move the mouse to expand the selection, OnSelectCell will not be called again.
Indeed MoveCurrent appears only in TCustomGrid.MouseDown.
Use the OnSelectCell event and set the CanSelect var parameter depending on whether the ARow parameter is what you want.
A nice solution
Check the options property on TStringGrid
There is an Option called 'goRangeSelect'
Set this to false using the object inspector
Or programatically this can be done by
StringGrid1.Options - [goRangeSelect];
This answer is not elegant at all, but it works.
My solution is NOT to use the PopupMenu property of the StringGrid. Instead I implemented my own PopUpMenu property. Works almost perfect. There is on small problem, the bottom of the pop-up menu appears next to the cursor and not its top.

How to Detect that the Mouse is unmoved and button still pressed?

In Delphi, I've added a Scrollbar component (oriented vertical) to the right side of my form.
I've added a Scrollbar OnChange event so I can change the view of the form and the position of the scrollbar thumb when the user clicks on the UpArrow or DownArrow button with his mouse, and this works fine.
But the OnChange event only seems to get triggered when the mouse button is initially pressed on the arrow.
I notice all scrollbar controls repeat the command and continue scrolling while the mouse remains pressed on the arrow, and I'd like to implement this behavior.
So how can I easily detect if the user has not moved the mouse and continues to press the mouse button while the mouse remains over the arrow?
Conclusion. Somehow something in the scrollbar in my project got corrupted. After I deleted the ScrollBar, and added it again, the problem vanished.
This is one of those tricky ones that took me a lot of time to solve. Thanks for your help. I'm closing this question.
Use the OnScroll event.
The following code adds 'xxx' to a memo as long as the mouse is held down on the scrollbar arrow button. Tested with Delphi 6.
procedure TForm1.ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode;
var ScrollPos: Integer);
begin
Memo1.Lines.Add( 'xxx' );
end;
The usual way to handle auto-repeating is to enable a TTimer and check in the OnTimer() event handler whether the action needs to be performed again, and to deactivate the timer if not. If you need sample code, I seem to remember that the SynEdit control used a similar technique for autoscrolling in drag and drop operations.
If a component does not encapsulate the behaviour you are looking for and you can't easily simulate the behaviour with the methods available you should really subclass the closest component that does most of what you need and add the behaviours that are missing.
I know that some extra work is involved but it really is the better way to go. Now with Delphi, I seem to recall that subclassed components needed a bit of extra work as well to be able to be used from the IDE for form design, maybe this has changed since version 7.

Resources