Другой способ узнать строку выбора в TStringGrid (она действительно единственная):
YourstringGrid.Selection.Top;
YourstringGrid.Selection.Bottom;
Если выбрана только одна строка, они должны совпадать.
Я никогда не вижу, что .Selection.···
терпит неудачу, хотя я видел, что YourstringGrid.Row, похоже, не может получить строку выбора, часто он возвращает -1, когда вы думаете, что он должен возвратить другие значения (см. 4 пункта в конце, чтобы понять, почему кажетсяпотерпеть неудачу, но это действительно не ошибка, когда он возвращает -1, ... это понятие недооценено).
Выделение и ячейка с foucs - это не одно и то же ... .Selection
дляselection, .Row
и .Col
предназначены для ячейки с фокусом и не имеют ничего общего с выделением, это может быть ячейка с фокусом, в то время как выделение представляет собой общий диапазон ячеек (оба понятия разные).
Кроме того, я обнаружил, что YourstringGrid.Row<>YourstringGrid.Selection.Top
может быть Истиной.Когда ячейка, которая имеет фокус, находится не в верхнем ряду выделения.
Некоторые взломы, приемы, код и т. Д., Показанные в Интернете, предназначены только для случая, когда goRowSelect=False
, если для него задано значение True, такие подпрограммыне работают должным образом, используйте их с осторожностью.
Подсказка: на TStringGrid с goRowSelect=True
очень глючно выбирать по коду больше, чем строка, при изменении .Selection
иногда не обновлять .Row
(они не изменяют фактическую ячейку, которая имеет фокус), поэтому, если кто-то хочет выбрать только одну строку, лучше присвоить значение строки непосредственно .Row
.
Помните: На TStringGrid с goRowSelect=True
говорить о том, какая ячейка имеет фокус, не имеет смысла, поэтому при ее кодировании они вообще не имеют в виду такую вещь (.Row
и .Col
не должны быть прочитаны, когда goRowSelect=True
).Другими словами: если у вас всегда выбран полный ряд, какой смысл проверять ячейку, в которой находится фокус, такой ячейки нет, это полная строка и т. Д. ... подумайте так, чтобы не рассердиться на БАГов навнутренняя реализация при смешивании сфокусированной ячейки на goRowSelect=True
TStringGrid.
Также худшее: с goRowSelect=True
и некоторыми комбинациями клавиш (Shift + Cursors) и щелчками мыши, вы можете сделать редкий выбор, например две или три ячейкив столбце, но не в полных строках;помните, что у него есть goRowSelect=True
, и сетка показывает только некоторые ячейки выбранных строк, и если вы прочитаете .Selection
, это говорит о том, что не все ячейки в строке выбраны (True=(TheGrid.FixedCols+#<TheGrid.Selection.Left)
), где # может быть больше 1. СноваОстерегайтесь таких ошибок ... я могу только сказать ... я всегда перехватываю изменения выбора и заставляю целые строки быть выбранными (я поставил код на OnSelectCell, чтобы убедиться, что все выделения всегда полные строки / с), см. простой код (обратите внимание, мне все равно, какая ячейка выбирается, по концепции выбор должен идти на полную строку или на полную строку, а не на ячейку, опять же редкая концепция, внутренняя реализация не думает, что вы хотите что-то делать при изменении выбранной ячейки, поэтомуу этого события, как предполагается, нет кода, я поместил этот код, чтобы исправить ошибку выбора, не являющуюся полной строкой / секциями):
procedure TYourForm.YourGridSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);
begin
YourGrid.Selection:=TGridRect(Rect(YourGrid.FixedCols,YourGrid.Selection.Top,YourGrid.FixedCols,YourGrid.Selection.Bottom));
end;
Упрощение: TStringGrid слишком много глючит, я поймал его, говоря'.Row = 13' в то же время .Selection.Top=2
и .Selection.Bottom=5
;как может быть активный ряд один за пределами выделения?и т. д. Это потому, что «.Row» (а также .Col
) не говорят о выбранной строке, говорят о том, какая ячейка имеет фокус, поэтому .Row
, чтобы узнать, какая строка выбрана, неверно в концепции ... выбудет видна строка ячейки с фокусом, ничего не имеющего отношения к ячейкам с точным отбором.
Я никогда не вижу неудач в этом:
- . Выбор. ··· всегда говоритВы выбрали выбранную область (область показана как выделенная)
- . Строка, если ей присвоено значение (а сетка имеет
goRowSelect=True
), будет выделена вся эта строка (я никогда не пробовал этого, не имея goRowSelect=True
),но только одна строка.
Не говоря уже о том, хотите ли вы много раз взломать TStringGrid и сделать его многострочным выбором с более чем одним непрерывным выбором одновременно (например, множественный выбор ListBox);из-за всех ошибок TStringGrid, связанных с управлением свойствами .Row и .Selection.
Для таких множественных сеток я всегда рекомендую использовать неофициальный компонент VCL вместо TStringGrid, если я не плохо помню, он называется TMultiSelectStringGrid, для него у вас есть свойство .Selected для каждой ячейки, строки и столбца, которая Читать / писать в состоянии. Это действительно прекрасно работает, когда вы хотите мульти-выбор с нажатой клавишей Ctrl, также отлично работает с многострочным выделением и выделением из нескольких столбцов ... просто сделайте цикл по строкам, столбцам или ячейкам, чтобы проверить, какие из них выбраны и ведьмы нет. У него также есть свойство .RightMouseSelect
(если я не помню плохо), которое делает щелчок правой кнопкой мыши, чтобы выбрать, и это хорошо.
Предупреждение, не весь код, который можно выбрать при щелчке правой кнопкой мыши, является правильным ... многим из них не важно, есть ли у вас множественный выбор или нет ... никогда не устанавливайте .Row
, если вы хотите сохранить больше, чем выбрана одна строка, просто проверьте, находится ли мышь вне выделенной области, прежде чем изменять .Selection
, иначе щелчок правой кнопкой мыши может сделать выбор для изменения ... так, как можно всплывающее меню для более чем одной строки (пример использования: вызывается пункт всплывающего меню удалить более одной записи одновременно).
Другими словами (код, который я действительно использую для стандарта VCL TStringGrid):
procedure TYourForm.YourGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
ACol,ARow:Integer;
begin
YourGrid.MouseToCell(X,Y,ACol,ARow);
if goRowSelect in YourGrid.Options
then begin // TStingGrig with full row selected, no individual cell must be selected
if (ARow<YourGrid.Selection.Top)
or
(YourGrid.Selection.Bottom<ARow)
then begin // Where clicked is outside the actual rows that are selected
YourGrid.Row:=ARow;
end;
end
else begin // TStingGrig where individual cells can be selected
if (ARow<YourGrid.Selection.Top)
or
(YourGrid.Selection.Bottom<ARow)
or
(ACol<YourGrid.Selection.Left)
or
(YourGrid.Selection.Right<ACol)
then begin // Where clicked is outside the actual selection
YourGrid.Selection:=TGridRect(Rect(ACol,ARow,ACol,ARow)); // Select the clicked cell
end;
end;
end;
Примечание: у меня действительно есть этот код для процедуры на модуле, и я вызываю эту процедуру, передавая ссылку на Grid и координаты X, Y; ну, если честно, то, что я использую, - это полный взлом TStringGrid с объявлением type TStringGrid=class(Grids.TStringGrid)
, поэтому я могу использовать визуальный дизайн и иметь дополнительные функции для всех них; просто убедитесь, что хак работает, чтобы добавить такой юнит в раздел interface
uses
в конце списка юнитов (или, по крайней мере, после гридов, а не до гридов).
Специальные подсказки для управления всплывающим меню были или не были показаны, и что всплывающее меню, чтобы показать:
- Сделайте это по событию
OnMouseDown
, никогда по OnMouseUp
, ни OnClick
и т. Д .; или всплывающее меню будет отображаться перед изменением выбора ... и иногда, когда изменение выбора (по коду) всплывающее окно будет скрыто сразу.
- Если сделано
OnMouseDown
, нет необходимости заставлять всплывающее меню показываться кодом, оно будет работать нормально; Более того, вы можете отменить показ всплывающего окна, например, если щелкнуть за пределами данных ячеек, или же вы можете иметь разные всплывающие окна для FixedCols, FixedRows, также для каждой ячейки вы можете иметь разные всплывающие окна (я говорю о всплывающих окнах времени разработки, вы также можете динамически создавать всплывающие записи до их показа и т. д.), всегда помещать код для того, что вы хотите сделать, в событие OnMouseDown
, рассказывая о меню операций, созданных во время разработки; если всплывающее окно создается во время выполнения, думайте так же: показывать или не показывать в OnMouseDown
, построение меню по собственному событию OnPopup
.
Основной трюк состоит в том, чтобы выполнить изменения выбора для события OnMouseDown
, оно запускается перед отображением всплывающего меню.
Ах, в моем коде я не возражаю против того, какая кнопка была нажата, так как если щелкнуть левой кнопкой мыши внутри нескольких выделенных строк, она также будет работать как обычно (мой код не вносит никаких изменений ни в выделение, ни в строку и т. Д.) на самом деле ничего не делает, см. if
s), но вы увидите изменения выбора только в одной строке.
Осторожно, выделение также может быть изменено на множественное выделение с помощью левой кнопки мыши, удерживая ее нажатой, затем переместите мышь и поднимите левую кнопку, которая выберет более одной ячейки / строки. Все эти способы, которыми пользователь должен делать выборки, делают внутреннюю реализацию стандартного компонента настолько ошибочной, что не все комбинации действий были приняты во внимание, пока он был внутренне закодирован.
Попробуйте нажать Ctrl и / или Shift, пока левая мышь нажата, и вы перемещаете мышь по стандартной сетке без кода вообще, код ecetp на OnMouseMove, чтобы показать .Row
, .Col
и .Selection.···
, будет увидеть то, что вы никогда не подумаете, будет возможно. Я вижу, один раз, когда сообщалось, что .Col
значение было несколько миллионов (недопустимое значение, поскольку у сетки только несколько столбцов), то же самое для .Row
(значение отличается от значения, когда происходит сбой в .Col).
Поэтому не верьте значениям, возвращаемым с .Row
и .Col
, если вы думаете о том, что является выделением (неправильное понятие, они выражают, какая ячейка имеет фокус, ничего не связано с тем, что выделение); но вы можете использовать их, чтобы выбрать одну и только одну строку или столбец (столбец, только если используется взломанная сетка, которая позволяет это, или использовать сетку с goRowSelect=False
и имитировать выбор столбца самостоятельно).
И, пожалуйста, всегда имейте это в виду (пожалуйста, делайте это всегда):
- Ячейка с фокусом (
.Row
и .Col
может сказать вам, какой из них) может находиться за пределами фактического выбора, да, она может быть вне (среди них очень трудно заставить потерпеть неудачу, это происходит , не нужно ничего кодировать, просто используя щелчок мышью и комбинации с Alt, Ctrl, Shift, Cursors и Spacebar). Так что не верьте .Row
и .Col
, чтобы знать что-либо о выборе (что неправильно по концепции), всегда используйте .Selection.···
.
Надеюсь, это поможет мне не набраться оборотов, пока я не пойму это:
.Selection.···
представляет только одну прямоугольную область выбранных ячеек (не имеет значения, если goRowSelect
- True или False).
.Selection:=TGrigRect(Rect(Left,Top,Right,Bottom));
- лучший способ изменить фактический выбор на другой (убедитесь, что вы сами Left<=Right
и Top<=Bottom
, иначе все может пойти очень плохо); думайте о коде как об этом огромном: .Selection:=TGrigRect(Rect(Min(Left,Right),Min(Top,Bottom),Max(Right,Left),Max(Bottom,Top));
(см. Min
и Max
, они в Maths
единице).
.Row
дает номер строки той специальной ячейки, на которой нарисован пунктирный прямоугольник, независимо от того, находится она внутри выделения или вне выделения, также может быть -1, если ни одна ячейка не имеет фокуса. Это не имеет ничего общего с выбором.
.Col
дает номер col той специальной ячейки, на которой нарисован пунктирный прямоугольник, независимо от того, находится она внутри выделения или вне выделения, также может быть -1, если ни одна ячейка не имеет фокуса. Это не имеет ничего общего с выбором.
Понимая, что четыре вещи, которые я могу получить, станут чем-то в прошлом. Мне потребовалось слишком много времени, чтобы понять две разные концепции: ячейка с фокусом («.Row» и «.Col») и выделенные ячейки (.Selection.···
).
P.D .: Будьте свободны поделиться этой информацией!