Когда пользователь нажимает Введите ключ в wxStyledTextCtrl
, кажется, что курсор всегда идет в начало строки (нулевой отступ), что, скорее всего, является ожидаемым поведением.
Я хочу иметь возможность писать код Script в следующем формате с отступами строки.
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.
Любые идеи были бы хорошы.
Нам нужно перехватить событие и добавить копию отступа из предыдущей строки в новую строку. Первый вопрос — какое событие использовать. При нажатии клавиши ввода запускаются следующие события:
С событиями char_hook и key_down ключ еще не был отправлен элементу управления, поэтому он не сможет предоставить необходимую информацию о положении. Элемент управления не должен быть изменен в событии stc_modified, поэтому мы не должны использовать эти события. К моменту события stc_painted курсор уже отрисован, поэтому он и событие key_up слишком поздние. И я узнал в другом ответе, что событие stc_updateui не будет работать.
Таким образом, в процессе исключения единственной возможностью является событие wxEVT_STC_CHARADDED. Следующий вопрос — что делать в этом обработчике событий. Я адаптировал код из Вот работать с 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));
}
}
}
Это может быть лучше, так как он физически подсчитывает пробелы и вкладки.
Заметка: Комментарии ниже указывают на фатальный недостаток в коде для этого ответа. Корректировать положение курсора в обработчике события 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 не предоставляет текущую позицию или строку, поэтому их необходимо пересчитать, прежде чем можно будет установить отступ. Я полагаю, что это можно оптимизировать, сохранив эти значения в обработчике события OnModified, а затем используя их в обработчике события UpdateUI.