Мне нужно показать ключ base64 в TMemo. К сожалению, невозможно правильно отобразить эту строку base64: она обрезается на каждом символе «/» при возврате каретки или на любом знаке «+», где систематически начинается новая строка! Я пробовал все, что в моих силах, чтобы сделать эту строку одной длинной фразой (без возврата каретки), но безуспешно. Как можно получить плоскую строку в base64 (без возврата каретки), если возможно, с автоматическим изменением размера при изменении размера формы и TMemo? Большое спасибо.
Fmx TMemo не может правильно отобразить строку base64
Ответы (1)
Для тех, кому интересно, код ниже: TForm с TMemo (memo). Это решение работает для меня для плоской строки Base64. Наконец-то больше нет обрыва строки при каждом / или +. Возможно, приведенное ниже решение нуждается в настройке, но оно работает достаточно для меня. Конечно, прежде чем обрабатывать строку b64 в приложении, ее необходимо отфильтровать, чтобы исключить CR-LF, но это нормально. Я использую события: OnKeyDown, OnResize, OnPainting TMemo. Я написал специальную функцию formatMemo(..), которая правильно выравнивает строки. Код принимает только правильные символы B64 и отфильтровывает ошибочные символы, если таковые имеются.
#define IS_B64(c) (isalnum(c) || (c == '/') || (c == '+') || (c == '='))
//Adjustments work for Courier New, standard size:
const float FW=7.2;//Font width
const diff=25;//Room for vert. scroll bar
//Gives the number of characters in one line of the TMemo:
// width : width in pixels where to put the line of chars
// font_sz : the average width of a character
// returns the number of characters by line of the TMemo
inline int nchars(int width, float font_sz)
{
return int(float(width-diff)/font_sz);
}//nchars
//---------------------------------------------------------------------------
//Formats the memo to a certain length of characters:
// *p : the memo to format
// nc : the number of characters for each line.
void formatMemo(TMemo *p, int nc)
{
if(p==0) return;
AnsiString src, dest;//UnicodeString is less fast...
//Filter everything as B64 only:
for(int i=1; i<=p->Text.Length(); ++i) {//Indexing is "1-based" like on Delphi (except on mobiles)
if(IS_B64(p->Text[i])) dest += p->Text[i];
}
p->Lines->Clear();//Erases everyting
int length=dest.Length(), units=length/nc, remain=length%nc;
for( int k=0 ; k<units ; ++k) {
p->Lines->Append( dest.SubString(1+k*nc, nc) );
}
if(remain) {
p->Lines->Append( dest.SubString(1+units*nc, remain) );
}
}//formatMemo
//---------------------------------------------------------------------------
void __fastcall TForm1::memoKeyDown(TObject *Sender, WORD &Key, System::WideChar &KeyChar,
TShiftState Shift)
{
//This event is triggered before the character is sent in Text.
//Saves caret position:
TCaretPosition p={memo->CaretPosition.Line, memo->CaretPosition.Pos};
memo->Tag=0;//Don't do a format.
if(Key==0 && !IS_B64(KeyChar))//Printable KeyChar
{
//Changes the entry into '0':
KeyChar='0';
KeyDown(Key,KeyChar,Shift);
//Put a backspace to erase:
Key=vkBack; KeyChar=0;
KeyDown(Key,KeyChar,Shift);
}
else memo->Tag=1;//Programs a format in the OnPainting
memo->SetFocus();
memo->CaretPosition=p;//Repositions the caret
}
//---------------------------------------------------------------------------
//In case of resize, reformat the TMemo
void __fastcall TForm1::memoResize(TObject *Sender)
{
formatMemo(memo, nchars(memo->Width,FW));
}
//---------------------------------------------------------------------------
void __fastcall TForm1::memoPainting(TObject *Sender, TCanvas *Canvas, const TRectF &ARect)
{
//We will use the Tag of the memo as a parameter, to plan a reformat.
if(memo->Tag){//A format is asked by OnKeyDown.
TCaretPosition p={memo->CaretPosition.Line, memo->CaretPosition.Pos};
formatMemo(memo, nchars(memo->Width,FW));
memo->SetFocus();
memo->CaretPosition=p;
memo->Tag=0;//Done
}
}
//---------------------------------------------------------------------------
person
Hugo
schedule
04.02.2016