2017-02-15 11 views
2

Когда пользователь нажимает клавишу ввода в wxStyledTextCtrl, кажется, что курсор всегда идет в начале строки (нулевой вдавливания), что, скорее всего, ожидаемое поведение.Как контролировать LineIndentation в wxStyledTextCtrl, когда пользователь нажимает Enter

Я хочу, чтобы писать код сценария в следующем формате, с отступом строки.

for i=1,10 do --say there is no indentation 
    i=i+1 -- now there is indentation via tab key 
    -- pressing enter should proceed with this level of indentation 
    print(i) -- same level of indentation with the previous code line 
end 

Я использую следующий код на C++ для управления отступом на очень базовом уровне.

void Script::OnKeyUp(wxKeyEvent& evt) 
{ 
    if ((evt.GetKeyCode() == WXK_RETURN || evt.GetKeyCode() == WXK_NUMPAD_ENTER)) { 
     long int col, line; 
     PositionToXY(GetInsertionPoint(), &col, &line); 
     int PreviousIndentation = GetLineIndentation(line-1); 
     SetLineIndentation(line, PreviousIndentation); 
     GotoPos(GetCurrentPos() + PreviousIndentation); 
    } 
} 

выше C++ код сохраняет уровень отступа, однако, курсор первым идет в начале строки, а затем на уровне отступа. При использовании других IDE это не происходит таким образом, как, например, переход к началу строки, а затем к уровню отступов. Скорее, курсор немедленно идет в/в соответствии с уровнем отступа. Есть ли способ, с помощью которого курсор может сразу перейти на уровень отступов, без первоначального перехода на нулевой уровень отступа.

Кстати, я попробовал EVT_STC_CHARADDED, который, кажется, как способ реализуется в ZeroBraneStudio, но когда Enter нажата клавиша evt.GetKeyCode() возвращает странное число и evt.GetUnicodeKey возвращается \0 и к тому же EVT_STC_CHARADDED событие вызывается дважды (я предполагаю, что из-за CR + LF).

Кстати, я использую WxWidgets-3.1.0 на Windows, 10.

Любые идеи будут оценены.

ответ

1

Нам нужно перехватить событие и добавить копию отступа от предыдущей строки к новой строке. Первый вопрос - какое событие использовать. Когда клавиша ввода нажата, следующие события увольняют:

  • wxEVT_CHAR_HOOK
  • wxEVT_KEY_DOWN
  • wxEVT_STC_MODIFIED - ModificationType: 0x00100000
  • wxEVT_STC_MODIFIED - ModificationType: 0x00000410
  • wxEVT_STC_MODIFIED - ModificationType: 0x00002011
  • wxEVT_STC_CHARADDED
  • wxEVT_STC_UPDATEUI
  • wxEVT_STC_PAINTED
  • wxEVT_KEY_UP

С char_hook и Key_Down событий, ключ не был отправлен в управление еще, так что он не будет в состоянии дать необходимую информацию о местоположении. Элемент управления не должен изменяться в событии stc_modified, поэтому мы не должны использовать эти события. Ко времени события stc_painted курсор уже был нарисован, поэтому он и событие key_up слишком запоздали. И я узнал в другом ответе, что событие stc_updateui не будет работать.

Таким образом, путем исключения, единственной возможностью является событие wxEVT_STC_CHARADDED. Следующий вопрос - что делать в обработчике события. Я применил код от here для работы с wxStyledTextCtrl.

void Script::OnCharAdded(wxStyledTextEvent& event) 
{ 
    int new_line_key=(GetEOLMode()==wxSTC_EOL_CR)?13:10; 

    if (event.GetKey() == new_line_key) 
    { 
     int cur_pos = GetCurrentPos(); 
     int cur_line = LineFromPosition(cur_pos); 

     if (cur_line > 0) 
     { 
      wxString prev_line = GetLine(cur_line-1); 
      size_t prev_line_indent_chars(0); 
      for (size_t i=0; i<prev_line.Length(); ++i) 
      { 
       wxUniChar cur_char=prev_line.GetChar(i); 

       if (cur_char==' ') 
       { 
        ++prev_line_indent_chars; 
       } 
       else if (cur_char=='\t') 
       { 
        ++prev_line_indent_chars; 
       } 
       else 
       { 
        break; 
       } 
      } 

      AddText(prev_line.Left(prev_line_indent_chars)); 
     } 
    } 
} 

Это может быть лучше, поскольку он физически учитывает пробелы и табуляции.

+0

Большое спасибо! Вчера я провел пару часов, чтобы исправить проблему пропусков, но не помог. Теперь он работает, как он должен работать. – macroland

+0

Извините за другой ответ. Как только я понял проблему, я потратил около 3 часов, пытаясь обойти это, прежде чем осознать, что это, вероятно, было безнадежным. –

+0

С недавними улучшениями в ответе, теперь это действительно очень хороший! – macroland

2

Примечание: Комментарии ниже указывают на фатальный недостаток в коде для этого ответа. Настройка позиции курсора в обработчике события UpdateUI, как я пытался сделать здесь, - плохая идея. Я опубликовал еще один ответ, который, надеюсь, будет работать лучше.

Я не могу гарантировать, что это лучший способ, но вот один из способов. Во-первых, это требует добавления целочисленного члена к вашему классу скриптов, чтобы он служил в качестве флага, указывающего, что необходимо добавить отступ. Ниже я назвал его «m_indentToAdd».

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

void Script::OnModified(wxStyledTextEvent& event) 
{ 
    int mt = event.GetModificationType(); 

    if(mt&wxSTC_MOD_INSERTTEXT && mt&wxSTC_PERFORMED_USER && event.GetLinesAdded()==1) 
    { 
     int cur_line = m_stc->LineFromPosition(event.GetPosition()); 
     int cur_indent = m_stc->GetLineIndentation(cur_line); 
     m_indentToAdd=cur_indent; 
    } 
} 

Чтобы избежать начала курсор в начале строки, а затем перейти к отступов, вы можете обработать событие wxEVT_STC_UPDATEUI и сброс положения есть:

void Script::OnUpdateUI(wxStyledTextEvent& event) 
{ 
    if(m_indentToAdd) 
    { 
     int cur_pos = m_stc->GetCurrentPos(); 
     int cur_line = m_stc->LineFromPosition(cur_pos); 
     m_stc->SetLineIndentation(cur_line, m_indentToAdd); 
     m_stc->GotoPos(cur_pos+m_indentToAdd); 

     m_indentToAdd=0; 
    } 
} 

Событие UpdateUI Безразлично» t обеспечить текущую позицию или линию, поэтому их необходимо пересчитать до того, как можно будет установить отступ. Я полагаю, это можно было бы оптимизировать, сохранив эти значения в обработчике событий OnModified, а затем используя их в обработчике события UpdateUI.

+0

Спасибо за ваш товар и ответ! Он работает хорошо, за исключением того, что если есть строка, расположенная под строкой, которую пользователь нажимает на ввод, например, пользователь находится на 5-й строке, а 6-я строка пуста (например, в редакторе есть 6-я строка), то отступ следует из 7-й строки а не 6-й. Если не было 6-й линии, нажатие enter делает то, что он должен делать. Я должен найти способ исправить это. Только один вопрос: я вижу, что вы используете 'LineFromIndentation', а не' GetLineIndentation'; есть ли конкретная причина для этого? – macroland

+0

Решение, которое я дал, было очень мало, но я не вижу проблемы проблемой из-за пустых строк. Для меня это работает во всех следующих случаях: следующая строка, пустая следующая строка и следующая строка не пусты, а с другим уровнем отступов. Если вы не можете найти исправление, можете ли вы дать более подробную информацию? –

+0

Также для вашего последнего вопроса вы спрашивали, почему я использую LineFromPosition вместо PositionToXY? Это не настоящая причина. PositionToXY реализуется с использованием LineFromPosition, поэтому они оба делают то же самое. –

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