textctrl.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,166 行 · 第 1/5 页
CPP
2,166 行
wxLogLastError(_T("EM_STREAMOUT"));
}
else // streamed out ok
{
// NUL-terminate the string because its length could have been
// decreased by wxRichEditStreamOut
*(wchBuf.data() + data.len) = L'\0';
// now convert to the given encoding (this is a possibly lossful
// conversion but what else can we do)
wxCSConv conv(encoding);
size_t lenNeeded = conv.WC2MB(NULL, wchBuf, 0);
if ( lenNeeded++ )
{
conv.WC2MB(wxStringBuffer(out, lenNeeded), wchBuf, lenNeeded);
}
}
#if !wxUSE_WCHAR_T
free(wchBuf);
#endif // !wxUSE_WCHAR_T
return out;
}
#endif // !wxUSE_UNICODE_MSLU
#endif // wxUSE_RICHEDIT
void wxTextCtrl::WriteText(const wxString& value)
{
DoWriteText(value);
}
void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
{
wxString valueDos;
if ( m_windowStyle & wxTE_MULTILINE )
valueDos = wxTextFile::Translate(value, wxTextFileType_Dos);
else
valueDos = value;
#if wxUSE_RICHEDIT
// there are several complications with the rich edit controls here
bool done = false;
if ( IsRich() )
{
// first, ensure that the new text will be in the default style
if ( !m_defaultStyle.IsDefault() )
{
long start, end;
GetSelection(&start, &end);
SetStyle(start, end, m_defaultStyle);
}
#if wxUSE_UNICODE_MSLU
// RichEdit doesn't have Unicode version of EM_REPLACESEL on Win9x,
// but EM_STREAMIN works
if ( wxUsingUnicowsDll() && GetRichVersion() > 1 )
{
done = StreamIn(valueDos, wxFONTENCODING_SYSTEM, selectionOnly);
}
#endif // wxUSE_UNICODE_MSLU
#if !wxUSE_UNICODE
// next check if the text we're inserting must be shown in a non
// default charset -- this only works for RichEdit > 1.0
if ( GetRichVersion() > 1 )
{
wxFont font = m_defaultStyle.GetFont();
if ( !font.Ok() )
font = GetFont();
if ( font.Ok() )
{
wxFontEncoding encoding = font.GetEncoding();
if ( encoding != wxFONTENCODING_SYSTEM )
{
// we have to use EM_STREAMIN to force richedit control 2.0+
// to show any text in the non default charset -- otherwise
// it thinks it knows better than we do and always shows it
// in the default one
done = StreamIn(valueDos, encoding, selectionOnly);
}
}
}
#endif // !wxUSE_UNICODE
}
if ( !done )
#endif // wxUSE_RICHEDIT
{
// in some cases we get 2 EN_CHANGE notifications after the SendMessage
// call (this happens for plain EDITs with EM_REPLACESEL and under some
// -- undetermined -- conditions with rich edit) and sometimes we don't
// get any events at all (plain EDIT with WM_SETTEXT), so ensure that
// we generate exactly one of them by ignoring all but the first one in
// SendUpdateEvent() and generating one ourselves if we hadn't got any
// notifications from Windows
UpdatesCountFilter ucf(m_updatesCount);
::SendMessage(GetHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT,
// EM_REPLACESEL takes 1 to indicate the operation should be redoable
selectionOnly ? 1 : 0, (LPARAM)valueDos.c_str());
if ( !ucf.GotUpdate() )
{
SendUpdateEvent();
}
}
}
void wxTextCtrl::AppendText(const wxString& text)
{
SetInsertionPointEnd();
WriteText(text);
#if wxUSE_RICHEDIT
// don't do this if we're frozen, saves some time
if ( !IsFrozen() && IsMultiLine() && GetRichVersion() > 1 )
{
// setting the caret to the end and showing it simply doesn't work for
// RichEdit 2.0 -- force it to still do what we want
::SendMessage(GetHwnd(), EM_LINESCROLL, 0, GetNumberOfLines());
}
#endif // wxUSE_RICHEDIT
}
void wxTextCtrl::Clear()
{
::SetWindowText(GetHwnd(), wxEmptyString);
#if wxUSE_RICHEDIT
if ( !IsRich() )
#endif // wxUSE_RICHEDIT
{
// rich edit controls send EN_UPDATE from WM_SETTEXT handler themselves
// but the normal ones don't -- make Clear() behaviour consistent by
// always sending this event
// Windows already sends an update event for single-line
// controls.
if ( m_windowStyle & wxTE_MULTILINE )
SendUpdateEvent();
}
}
#ifdef __WIN32__
bool wxTextCtrl::EmulateKeyPress(const wxKeyEvent& event)
{
SetFocus();
size_t lenOld = GetValue().length();
wxUint32 code = event.GetRawKeyCode();
::keybd_event((BYTE)code, 0, 0 /* key press */, 0);
::keybd_event((BYTE)code, 0, KEYEVENTF_KEYUP, 0);
// assume that any alphanumeric key changes the total number of characters
// in the control - this should work in 99% of cases
return GetValue().length() != lenOld;
}
#endif // __WIN32__
// ----------------------------------------------------------------------------
// Clipboard operations
// ----------------------------------------------------------------------------
void wxTextCtrl::Copy()
{
if (CanCopy())
{
::SendMessage(GetHwnd(), WM_COPY, 0, 0L);
}
}
void wxTextCtrl::Cut()
{
if (CanCut())
{
::SendMessage(GetHwnd(), WM_CUT, 0, 0L);
}
}
void wxTextCtrl::Paste()
{
if (CanPaste())
{
::SendMessage(GetHwnd(), WM_PASTE, 0, 0L);
}
}
bool wxTextCtrl::HasSelection() const
{
long from, to;
GetSelection(&from, &to);
return from != to;
}
bool wxTextCtrl::CanCopy() const
{
// Can copy if there's a selection
return HasSelection();
}
bool wxTextCtrl::CanCut() const
{
return CanCopy() && IsEditable();
}
bool wxTextCtrl::CanPaste() const
{
if ( !IsEditable() )
return false;
#if wxUSE_RICHEDIT
if ( IsRich() )
{
UINT cf = 0; // 0 == any format
return ::SendMessage(GetHwnd(), EM_CANPASTE, cf, 0) != 0;
}
#endif // wxUSE_RICHEDIT
// Standard edit control: check for straight text on clipboard
if ( !::OpenClipboard(GetHwndOf(wxTheApp->GetTopWindow())) )
return false;
bool isTextAvailable = ::IsClipboardFormatAvailable(CF_TEXT) != 0;
::CloseClipboard();
return isTextAvailable;
}
// ----------------------------------------------------------------------------
// Accessors
// ----------------------------------------------------------------------------
void wxTextCtrl::SetEditable(bool editable)
{
HWND hWnd = GetHwnd();
::SendMessage(hWnd, EM_SETREADONLY, (WPARAM)!editable, (LPARAM)0L);
}
void wxTextCtrl::SetInsertionPoint(long pos)
{
DoSetSelection(pos, pos);
}
void wxTextCtrl::SetInsertionPointEnd()
{
// we must not do anything if the caret is already there because calling
// SetInsertionPoint() thaws the controls if Freeze() had been called even
// if it doesn't actually move the caret anywhere and so the simple fact of
// doing it results in horrible flicker when appending big amounts of text
// to the control in a few chunks (see DoAddText() test in the text sample)
if ( GetInsertionPoint() == GetLastPosition() )
{
return;
}
long pos;
#if wxUSE_RICHEDIT
if ( m_verRichEdit == 1 )
{
// we don't have to waste time calling GetLastPosition() in this case
pos = -1;
}
else // !RichEdit 1.0
#endif // wxUSE_RICHEDIT
{
pos = GetLastPosition();
}
SetInsertionPoint(pos);
}
long wxTextCtrl::GetInsertionPoint() const
{
#if wxUSE_RICHEDIT
if ( IsRich() )
{
CHARRANGE range;
range.cpMin = 0;
range.cpMax = 0;
::SendMessage(GetHwnd(), EM_EXGETSEL, 0, (LPARAM) &range);
return range.cpMin;
}
#endif // wxUSE_RICHEDIT
DWORD Pos = (DWORD)::SendMessage(GetHwnd(), EM_GETSEL, 0, 0L);
return Pos & 0xFFFF;
}
wxTextPos wxTextCtrl::GetLastPosition() const
{
int numLines = GetNumberOfLines();
long posStartLastLine = XYToPosition(0, numLines - 1);
long lenLastLine = GetLengthOfLineContainingPos(posStartLastLine);
return posStartLastLine + lenLastLine;
}
// If the return values from and to are the same, there is no
// selection.
void wxTextCtrl::GetSelection(long* from, long* to) const
{
#if wxUSE_RICHEDIT
if ( IsRich() )
{
CHARRANGE charRange;
::SendMessage(GetHwnd(), EM_EXGETSEL, 0, (LPARAM) &charRange);
*from = charRange.cpMin;
*to = charRange.cpMax;
}
else
#endif // !wxUSE_RICHEDIT
{
DWORD dwStart, dwEnd;
::SendMessage(GetHwnd(), EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
*from = dwStart;
*to = dwEnd;
}
}
bool wxTextCtrl::IsEditable() const
{
// strangely enough, we may be called before the control is created: our
// own Create() calls MSWGetStyle() which calls AcceptsFocus() which calls
// us
if ( !m_hWnd )
return true;
long style = ::GetWindowLong(GetHwnd(), GWL_STYLE);
return (style & ES_READONLY) == 0;
}
// ----------------------------------------------------------------------------
// selection
// ----------------------------------------------------------------------------
void wxTextCtrl::SetSelection(long from, long to)
{
// if from and to are both -1, it means (in wxWidgets) that all text should
// be selected - translate into Windows convention
if ( (from == -1) && (to == -1) )
{
from = 0;
to = -1;
}
DoSetSelection(from, to);
}
void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret)
{
HWND hWnd = GetHwnd();
#if wxUSE_RICHEDIT
if ( IsRich() )
{
CHARRANGE range;
range.cpMin = from;
range.cpMax = to;
::SendMessage(hWnd, EM_EXSETSEL, 0, (LPARAM) &range);
}
else
#endif // wxUSE_RICHEDIT
{
::SendMessage(hWnd, EM_SETSEL, (WPARAM)from, (LPARAM)to);
}
if ( scrollCaret && !IsFrozen() )
{
#if wxUSE_RICHEDIT
// richedit 3.0 (i.e. the version living in riched20.dll distributed
// with Windows 2000 and beyond) doesn't honour EM_SCROLLCARET when
// emulating richedit 2.0 unless the control has focus or ECO_NOHIDESEL
// option is set (but it does work ok in richedit 1.0 mode...)
//
// so to make it work we either need to give focus to it here which
// will probably create many problems (dummy focus events; window
// containing the text control being brought to foreground
// unexpectedly; ...) or to temporarily set ECO_NOHIDESEL which may
// create other problems too -- and in fact it does because if we turn
// on/off this style while appending the text to the control, the
// vertical scrollbar never appears in it even if we append tons of
// text and to work around this the only solution I found was to use
// ES_DISABLENOSCROLL
//
// this is very ugly but I don't see any other way to make this work
long style = 0;
if ( GetRichVersion() > 1 )
{
if ( !HasFlag(wxTE_NOHIDESEL) )
{
// setting ECO_NOHIDESEL also sets WS_VISIBLE and possibly
// others, remember the style so we can reset it later if needed
style = ::GetWindowLong(GetHwnd(), GWL_STYLE);
::SendMessage(GetHwnd(), EM_SETOPTIONS,
ECOOP_OR, ECO_NOHIDESEL);
}
//else: everything is already ok
}
#endif // wxUSE_RICHEDIT
::SendMessage(hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
#if wxUSE_RICHEDIT
// restore ECO_NOHIDESEL if we changed it
if ( GetRichVersion() > 1 && !HasFlag(wxTE_NOHIDESEL) )
{
::SendMessage(GetHwnd(), EM_SETOPTIONS,
ECOOP_AND, ~ECO_NOHIDESEL);
if ( style != ::GetWindowLong(GetHwnd(), GWL_STYLE) )
::SetWindowLong(GetHwnd(), GWL_STYLE, style);
}
#endif // wxUSE_RICHEDIT
}
}
// ----------------------------------------------------------------------------
// Working with files
// ----------------------------------------------------------------------------
bool wxTextCtrl::LoadFile(const wxString& file)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?