2010-08-19 5 views
2

У меня возникли проблемы с помощью меню TStringGrid и ВсплывающегоDelphi: StringGrid, положение и Контекстное меню

Я хочу знать строки/столбец ячейки, который был последним активным, когда выбрать элемент из моего всплывающего окна меню. Однако, когда я нажимаю на всплывающее меню, StringGrid.Row возвращается как -1.

Я попытался использовать MouseToCell как часть OnClick, но даже после установки SG.Row он по-прежнему возвращается как -1 в подпрограммах меню PopUp ... Я подозреваю, что проблема заключается в том, что Grid потеряла фокус.

Есть ли какие-либо решения для этого, которые не требуют установки OnClick глобальной переменной?

Я использую список действий, связанный с пунктами всплывающего меню, чтобы убедиться, что действия согласуются между панелью инструментов и всплывающих меню

ответ

7

Я боюсь, что я не совсем понимаю, что вы имеете в виду , Когда я щелкнул левой кнопкой мыши ячейку в строковой сетке, она будет выбрана, но не тогда, когда я щелкнул ее правой кнопкой мыши. Когда я щелкнул правой кнопкой мыши, появится всплывающее меню (если оно назначено), и по адресу MenuItemClick. Я могу легко прочитать row и col. См. example video.

I Угадать что вы действительно этого хотите: вы хотите щелкнуть правой кнопкой мыши, чтобы изменить активную ячейку, а также щелкнуть левой кнопкой мыши. Это легко сделать:

procedure TForm1.StringGrid1MouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    if Button = mbRight then 
    StringGrid1.Perform(WM_LBUTTONDOWN, 0, MakeLParam(Word(X), Word(Y))); 
end; 
+2

Я не думаю, что вам действительно нужно проверить, заменены ли кнопки. Когда кнопки переключаются, нажатие левой кнопки генерирует сообщения правой кнопки и наоборот. Когда кнопки меняются местами и нажата левая кнопка, аргумент 'Button' уже будет' mbRight'. –

+0

@ Rob Kennedy: Да, я понял, что во время сна ... –

+0

Если я попытаюсь заставить это работать, тогда Left Click перестанет работать, и я получаю переполнение стека! Без вышеуказанного я нажимаю на ячейку, и «активная граница» перемещается в выбранную ячейку. Если я затем щелкните правой кнопкой мыши и выберите пункт меню, то значение, указанное как StringGrid.Col, равно -1 –

0

В одном из моих TStringGrid управления на основе я использую MouseDown/MouseUp событие для обработки этого всплывающего меню, потому что у меня есть два различных контекстное меню, в зависимости от того, какой области TStringGrid вас» кликнул. Работает как шарм. Просто убедитесь, что вы звоните унаследовано ПЕРЕД кодом.

-
Обратите внимание: что-то странное в том порядке, в котором вызываются события при появлении контекстного меню. Точнее, когда вы нажимаете RMB, и всплывающее меню появляется, событие MouseUp не вызывается немедленно. Он вызывается в следующий раз, когда вы нажимаете кнопку мыши (любая кнопка).

Смотрите это также: TStringGrid - OnMouseUp is not called!

0

Хм ... Я не могу воспроизвести проблему в моем D2010.

Быстрая мысль о том, что, возможно, проблема возникает из-за того, что у вас не было выбранных строк? Предварительно задал бы строку StringGrid, скажем, 0 в своей помощи Form OnCreate?

0

Если вы хотите/нужно щелкнуть правой кнопкой мыши на ячейки перемещения фокуса на него (как это обычно делается с левой кнопкой мыши), вы можете использовать код я использую для этого:

type TStringGridHacked=class(Grids.TStringGrid); // This is to have access to hidden (and very usefull) methods, like MoveCol, MoveRow, FocusCell, etc 
procedure TMyForm.TheStringGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
var 
    ACol,ARow:Integer; 
begin 
    if mbRight=Button 
    then begin // Right mouse button clicked 
       TheStringGrid.MouseToCell(X,Y,ACol,ARow); // Convert X,Y coordinates of mouse to cell Col & Row 
       if (FixedCols<=ACol)and(FixedRows<=ARow) 
       then begin // Cell is not a header one 
         TStringGridHacked(TheStringGrid).FocusCell(ACol,ARow,True); // Send focus to such cell doing only one move, so triggering SelectCell only once 
        end; 
      end; 
end; 

Я использую эту Hack type TStringGridHacked=class(Grids.TStringGrid) для долгое, долгое время, так как я нашел его в Интернете.

Я положил такой хак (объявление типа) сразу после реализации (если мне это нужно более одного раза на одном устройстве) или как в коде перед процедурой (если мне это нужно только один раз); оба способа работают отлично и делают код более понятным.

1

Другой способ узнать строку выбора на TStringGrid (это на самом деле только один):

YourstringGrid.Selection.Top; 
YourstringGrid.Selection.Bottom; 

Если есть только одна строка выбрана, они должны совпадать.

Я никогда не видел .Selection.··· сбой, пока я видел, почему кажется неудачным, но это действительно не сбой, когда он возвращает -1, ... это концепция bas underod).

Выбор и клетки с foucs не то же самое ... .Selection для выбора, .Row и .Col являются для ячейки с фокусом и не имеет никакого отношения, связанные с выбором, это может быть клетка с фокусом в то время как выбор будет полный различный диапазон ячеек (оба - разные концепции).

Кроме того, я обнаружил, что YourstringGrid.Row<>YourstringGrid.Selection.Top может быть правдой. Когда ячейка, которая имеет фокус, находится не в верхней строке выбора.

Некоторые хаки, трюки, код и т. Д., Показанные в Интернете, предназначены только для тех случаев, когда goRowSelect=False, если он установлен в True, такие процедуры не работают хорошо, используйте их с осторожностью.

Подсказка: На TStringGrid, который имеет goRowSelect=True это очень плохо, чтобы выбрать с помощью кода больше, чем подряд, меняя .Selection иногда не обновлять .Row (они не изменяют фактический элемент, который имеет фокус), так что если кто-то хочет для выбора только одной строки лучше назначить значение строки непосредственно .Row.

Помните: На TStringGrid с goRowSelect=True говорить о том, что клетка имеет фокус не имеет Sence, поэтому при кодировании его они не имеют в виду такие вещи вообще (.Row и .Col не должно быть, когда goRowSelect=True прочитанные). Другими словами: если у вас всегда есть полная строка, выбранная, чтобы проверить ячейку, в которой есть фокус, нет такой ячейки, это полная строка и т. Д., Подумайте, что это не должно быть безумным из-за ошибок внутренняя реализация при смешении сфокусированной ячейки на goRowSelect=True TStringGrid.

Также худшее: с goRowSelect=True и некоторыми комбинациями клавиш (Shift + Cursors) и щелчками мыши вы можете делать редкие выборы, например две или три ячейки в столбце, но не полные строки; помните, что он имеет goRowSelect=True, и сетка отображает только некоторые ячейки выбранных строк. Если вы читаете .Selection, это говорит вам, что не все ячейки в строке выбраны (True=(TheGrid.FixedCols+#<TheGrid.Selection.Left)), где # может быть больше 1. Опять же, остерегайтесь таких ошибок. .. я могу только сказать ... я все время выбираю выбор ловушки и заставляю полные строки быть выбранными (я помещаю код на OnSelectCell, чтобы весь выбор был всегда полным числом строк), см. простой код (обратите внимание, что мне все равно, что ячейка выбирается по понятию, выбор должен идти в полную строку или полные строки, а не в ячейку, снова редкая концепция, внутренняя реализация не думает, что вы хотите что-то сделать, когда выбранные изменения ячейки, поэтому это событие не должно иметь код, я помещаю этот код в FIX BUG выбора, который не является полным числом строк):

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) не говорит о выбранной строке, расскажет о том, какая ячейка имеет фокус, поэтому, видя, какая строка выбрана, ошибочна в концепции ...вы увидите строку ячейки, которая имеет фокус, ничего не связанное с клетками выбора acutal.

Я никогда не видел эту неудачу вещи:.

  • .Selection ··· ВСЕГДА говорит вам выделенную область (область, показанную по выбору)
  • .Row если присвоено значение (и сетка имеет goRowSelect=True), выбрана вся строка (я никогда не пробовал это, не имея goRowSelect=True), но только одну строку.

Не говоря уже о том, что вы хотите многократно взломать TStringGrid и сделать его многострочным выбором с более чем одним выбором contiguos в одно и то же время (например, ListBox multi select); что делает вещи очень chazy из-за всех ошибок TStringGrid имеет .Row и .Selection properties management.

Для таких многоканальных сеток я рекомендую всегда использовать компонент VCL без текста, а не TStringGrid, если я не помню, что он называется TMultiSelectStringGrid, на нем у вас есть свойство .Selected для каждой ячейки, строки и столбца это возможность чтения/записи. Это действительно отлично работает, когда вы хотите, чтобы мульти-выбор нажал клавишу Ctrl, также отлично работает с выбором нескольких строк и выбором нескольких столбцов ... просто выполните цикл над строками, столбцами или ячейками, чтобы проверить, что ведьмы выбраны и ведьмы нет. Он также имеет свойство .RightMouseSelect (если я не помню плохо), что делает правый щелчок, чтобы выбрать, и он преуспевает.

Предупреждение. Не все коды, чтобы выбрать правильный щелчок, верны ... многие из них не заботятся, если у вас есть множественный выбор или нет ... никогда не устанавливайте .Row, если вы хотите использовать более одного строка выбрана, просто проверьте, не находится ли мышь за пределами выбора до изменения .Selection. Еще один щелчок правой кнопкой мыши может сделать выбор для изменения ... так, как можно всплывающее меню для более одной строки (пример использования: всплывающее меню с названием delete для более чем одна запись одновременно).

Другими словами (код я действительно использовать для 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; 

Примечание: Я действительно есть этот код на процедуры на единицу и называют эту процедуру, проходящую координатной сетки и X, Y координаты; хорошо сказать истинную истину, что единица, которую я использую, является полным взломом TStringGrid с объявлением как type TStringGrid=class(Grids.TStringGrid), поэтому я могу использовать визуальный дизайн и получать дополнительные функции на всех из них; просто убедитесь, что взломать работу, чтобы добавить такой блок в раздел interfaceuses в конце списка устройств (или, по крайней мере, после Grids, никогда ранее Grids).

Специальные подсказки для управления Всплывающее меню было или нет не было показано, что и Контекстное меню, чтобы показать:

  • Делайте это на событие OnMouseDown, никогда на OnMouseUp, ни OnClick, и т.д .; или всплывающее меню будет отображаться до изменения выбора ... и sometines, когда выбор изменяется (по коду), всплывающее окно будет скрыто.
  • Если сделано OnMouseDown, нет необходимости принудительно отображать всплывающее меню по коду, он будет делать это нормально; Кроме того, вы можете отменить всплывающее окно, которое будет отображаться, например, если вы щелкнули вне данных ячеек или также можете иметь разные всплывающие окна для FixedCols, FixedRows, также для каждой ячейки вы можете иметь другое всплывающее окно (я говорю о всплывающих окнах времени разработки, вы также можете динамически создавать всплывающие записи перед отображением и т. д.), поместите код для того, что вы хотите делать всегда на событии OnMouseDown, говоря о меню opoup, созданном во время разработки; если всплывающее окно создается во время выполнения, подумайте о том же: покажите или не покажите на OnMouseDown, постройте меню в своем меню OnPopup.

Основной трюк заключается в том, чтобы сделать выборные действия на событии OnMouseDown, он запускается перед отображением всплывающего меню.

Ах, в моем коде я не против, какая кнопка была нажата, так как если бы щелкнул левой кнопкой мыши внутри нескольких выбранных строк, он также будет действовать как нормальный (мой код не вносит никаких изменений в выбор, ни в строку, и т.д. он действительно ничего не делает, см. раздел if), но вы увидите, что выбор изменяется только на одну строку.

Остерегайтесь, выбор также может быть изменен на многократный выбор мышью слева вниз, поддерживается, а затем перемещать мышь и поднимать левую кнопку, которая будет выбирать более одной ячейки/строки. Все это означает, что пользователь должен делать выбор, делает внутреннюю реализацию стандартного компонента такой ошибкой, а не все комбинации действий были приняты во внимание, когда они были внутренне закодированы.

Попробуйте нажать Ctrl и или Shift, в то время как левая мыши нажата, и вы перемещаете мышь на стандартной сетке, без кода вообще, код ecetp на OnMouseMove показать .Row, .Col и .Selection.···, будет видеть, что вы не будете когда-либо подумать было бы возможно. Я вижу один раз, когда значение .Col составляло несколько миллинов (несущественное значение, так как сетка имеет только несколько столбцов), то же самое для .Row (другое значение, чем при неудаче на .Col).

Так что не верьте значениям, возвращаемым с .Row и .Col, если вы думаете о получении того, что является выбором (неправильная концепция, они выражают, какая ячейка имеет фокус, ничего не связано с тем, какой выбор); но вы можете использовать их для выбора одного и только одного столбца или столбца (столбец, только если использовать разрезанную решетку, разрешающую его, или использовать сетку с goRowSelect=False и имитировать выбор столбца по своему усмотрению).

И пожалуйста, ВСЕГДА иметь в виду, что это (пожалуйста, сделайте это ВСЕГДА):

  • Клетка, которая имеет фокус (.Row и .Col может сказать, какая из них) может быть вне фактического выбора, да , это может быть (из-за того, что очень сложно заставить это сбой, это происходит, не нужно ничего кодировать, просто используя щелчок мышью и комбинации с Alt, Ctrl, Shift, Cursors и пробел могут случиться). Поэтому не доверяйте .Row ни .Col, чтобы знать что-нибудь о выборе (что неправильно в концепции), всегда используйте .Selection.···.

Надеется, что это помогает не получать headage, как я имел, пока я не понимаю этого:

  1. .Selection.··· representes только одна прямоугольной области ячеек, выбранных (не ума, если goRowSelect является истинным или ложным).
  2. .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 единицах).
  3. .Row дает номер строки этой специальной ячейки, у которой есть пунктирный прямоугольник, нарисованный на нем, независимо от того, находится ли он внутри выделения или вне выделения, также может быть -1, если ни одна ячейка не имеет фокуса. Он не имеет ничего общего с выбором.
  4. .Col дает номер столбца этой специальной ячейки, у которого есть пунктирный прямоугольник, нарисованный на нем, независимо от того, находится ли он внутри выделения или вне выделения, также может быть -1, если ни одна ячейка не имеет фокуса. Он не имеет ничего общего с выбором.

Понимая, что четыре вещи, я могу получить заголовки, чтобы быть чем-то в прошлом. Мне было слишком много, чтобы понять, что две разные концепции: ячейка, в которой есть фокус («.Row» и «.Col») и выбранные ячейки (.Selection.···).

P.D .: Бесплатно делиться этой информацией!

Смежные вопросы