TStringGrid dirty hack - Restricting the selection to one single row - delphi

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.

Related

Why OnHScrollChange is not fired in stringgrid in Firemonkey?

Why OnHScrollChange is not fired in stringgrid in Firemonkey? How should i catch the scrolling event in Stringgrid?
OnHScrollChange is fired when you scroll with the scrollbar thumbgrip or its buttons. It is however not fired by changing the selection with the left and right arrow keys, even if that would result in the thumbgrip of the scrollbar being moved.
If your question is about the latter situation, I kind of agree with you that it should trigger the OnHScrollChange, but then again, I have no idea of any design decisions. You may want to enter a report at Embarcadero's Quality Portal and see how they respond.
Another possibility is to use the OnViewportPositionChange event instead which fires however the viewport position changes. The caveat is that it fires also on vertical scrolling. If this is ok for you then that is your solution.

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.

combobox steal keyboard from main window in pyqt

I'm writing a small pyqt program. I want the main window to to react to arrow movement. I added an event to my MainGui class, keyPressEvent, that handle this. The event work fine as long as I don't press certain buttons such as Key_Up or Key_Down are directed to my (currently only) QComboBox and not to my mainGui. I tried to give the focus to mainGui after each paintEvent but then I need to double click on buttons/comboBox.
Then I tried to use the MousePressEvent to check if a certain element is under the mouse. This work fine with the comboBox, but not with the button.
So, how can I direct key events to the mainGui or give the focus to QButtons?
I used eventFilter to identify when the mouse enter the QPushButton and give it focus:
def eventFilter(self,source,event):
if event.type() == QtCore.QEvent.HoverMove:
if self.execButton.underMouse():
self.execButton.setFocus()
self.keepFocus=False
else :
self.keepFocus=True
keepFocus is a flag I initialized in the __init__ function of the class. I added this part at the paintEvent function
if self.keepFocus:
self.setFocus()
else:
self.keepFocus = True
Now, I keep the focus at the MainGui and I only give it to the button when the mouse hove over it. If I do another action (like pressing a mouse button or a keyboard key) the focus is given back to the MainGui. This will create some buggy filling (For example, I need to press twice a keyboard key before the first response) but this is workable.

Show different popup menu depending on what column the mouse is over in a Delphi TListView control?

I have a Delphi 6 application that has a TJvListView control. I have a popup menu tied to that control via the control's PopupMenu property. What I would like to do is show a different popup menu based on which column the user had the mouse over when they right clicked, with the additional option to not show a popup menu at all if the current column does not need one. How can I do this?
Thanks to this detailed sample by Remy Lebeau on in-place editing in a TListView I know what row and column the mouse is over except for one wrinkle. The mouse down event where I determine the current row and column occurs after the popup menu is exited.
I now need to know two things. First, how can I get some event to fire before the popup menu shows after a right mouse click so I can record the current list view row and column and suppress the popup menu if I want to, and second, how I can show a different popup based on the current column. I am hoping to avoid having to write a bunch of mini-forms instead of using the TListView PopupMenu property and supporting code. Is there a simple solution, perhaps some fancy footwork in a sub-class I should create around TJvListView?
You could perform the detection in mousemove instead of mousedown/Click and change the popupmenu depending.
You also could remove any popupmenu and call the wished via p.pupup in mousedown as you desire.

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