1

私は CRichEditCtrl を持っています (実際には、私が定義した CRichEditCtrl のサブクラスであるクラスを持っています)。このクラスには、水平スクロール バーと垂直スクロール バーの両方を備えた多数のテキスト行が入力されています。このコントロールの目的は、検索対象の文字列を、左右に n 文字の大きなテキストで表示することです (たとえば、ユーザーが「the」を検索すると、「the」のすべてのインスタンスのリストが表示されます)。 " (n = 100 の場合) コンテキストを提供するために、見つかった各インスタンスの左右に 100 文字を含むテキスト内)。

クエリ文字列は、各行の間に並べる必要があります。このプログラムが Unicode をサポートする前は、フォントを Courier に設定するだけでうまくいきましたが、Unicode のサポートを有効にしたので、これは機能しなくなりました。

等幅フォントを使用してみましたが、私が知る限り、すべての文字に対応するものはありません。ラテン文字にはすべて 1 つのサイズがあり、漢字には別のサイズがあるように思えます (すべてのラテン文字が並んでいるテキスト行とすべて漢字が並んでいるテキスト行に気付きましたが、両方が並んでいる行は並んでいません) )。

また、テキストを中央揃えにしてみました。各行のクエリ文字列は正確に中央にあるため、すべて整列する必要がありますが、これを機能させることができないようです.SetParaFormat呼び出しは無視されるようです. そのために使用したコードは次のとおりです。

long spos, epos;
GetSel(spos, epos);
PARAFORMAT Pfm;
GetParaFormat(Pfm);

Pfm.dwMask = (Pfm.dwMask | PFM_ALIGNMENT);
Pfm.wAlignment = PFA_CENTER;

SetSel(0, -1);
SetParaFormat(Pfm);

SetSel(spos, epos);

テキストがctrlに挿入されるたびにこれを行いますが、プログラムには影響しません。

中国語とラテン文字が散在している場合でも、テキストの各行にクエリ単語を並べる方法はありますか? (およびおそらく他の文字セット)

4

2 に答える 2

2

http://msdn.microsoft.com/en-us/library/bb787940(v=vs.85).aspx、特にタブストップを設定できる(または)構造体のcTabCountおよびrgxTabsメンバーを参照してください。PARAFORMATPARAFORMAT2

于 2011-08-04T15:04:50.340 に答える
0

さて、私はそれを解決することができました。将来の参考のために、ここに私がやったことがあります:

最初に、等幅フォントを見つけようとしましたが、本当に等幅フォント (ラテン文字と漢字が同じ幅) を見つけることができませんでした。

次に、テキストをウィンドウの中央に配置しようとしました。Auto HScroll を true (リッチ エディット コントロール用に定義された ES_AUTOHSCROLL) に設定すると、setParaFormat がテキストを中央に配置しようとしても無視されることに気付くまで、これを行うことができませんでした。無効にして、描画可能なテキスト領域のサイズを手動で設定した後、テキストを中央に配置できました。念のため、リッチ エディット ボックスで描画可能領域の幅を設定するために使用したコードを次に示します。

CDC* pDC = GetDC();    
long lw = 99999999;
SetTargetDevice(*GetDC(), lw);

テキストの中央揃えが機能するかどうかをテストできるように、 lw を任意に大きく設定しました。それはしませんでした。結局のところ、リッチ エディット コントロールがテキストを中央揃えにすると、文字数ではなく、テキストの描画幅に基づいて配置されます。クエリ文字列の両側に同じ数の文字があるため、文字列が中央に配置されると思いましたが、そうではありませんでした。

私が試した最終的な解決策は、ymett によって提案されたものでした。少し調整した後、すべてのテキストがリッチ エディット コントロールに挿入された後に呼び出される alignText() という関数を思いつきました。関数は次のとおりです (注: コントロールの各行には、この関数が呼び出される前にタブが挿入されていました。1 つは行の先頭に、もう 1 つはクエリ文字列の後に挿入されています。たとえば、"string1-query-string2" は "\tstring1-query\t- string2")

void CFormViewConcordanceRichEditCtrl::alignText()
{

    long maxSize = 0;
    CFont font;
    LOGFONT lf = {0};
    CHARFORMAT cf = {0};
    this->GetDefaultCharFormat(cf);

    //convert a CHARFORMAT struct into a LOGFONT struct
    if (cf.dwEffects & CFE_BOLD)
        lf.lfWeight = FW_BOLD;
    else
        lf.lfWeight = FW_NORMAL;
    if (cf.dwEffects & CFE_ITALIC)
        lf.lfItalic = true;
    if (cf.dwEffects & CFE_UNDERLINE)
        lf.lfUnderline = true;
    if (cf.dwEffects & CFE_STRIKEOUT)
        lf.lfStrikeOut = true;
    lf.lfHeight = cf.yHeight;
    _stprintf(lf.lfFaceName, _T("%s"), cf.szFaceName);
    lf.lfCharSet = DEFAULT_CHARSET;
    lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
    font.CreateFontIndirect(&lf);

    //create a display context
    CClientDC dc(this);
    dc.SetMapMode(MM_TWIPS);
    CFont *pOldFont = dc.SelectObject(&font);

    //find the line that as the longest preceding string when drawn
    for(int i = 0; i < m_pParent->m_nDataArray; i++)
    {
        CString text = m_pParent->DataArray[i].text.Left(BUFFER_LENGTH + m_pParent->generateText.GetLength());
        text.Replace(_T("\r"), _T(" "));
        text.Replace(_T("\n"), _T(" "));
        text.Replace(_T("\t"), _T(" "));

        CRect rc(0,0,0,0);
        dc.DrawText(text, &rc, DT_CALCRECT);

        int width = 1.0*cf.yHeight/fabs((double)rc.bottom - rc.top)*(rc.right - rc.left);
        width = dc.GetTextExtent(text).cx;
        if(width > maxSize)
            maxSize = width;
    }

    dc.SelectObject(pOldFont);

    //this calulates where to place the first tab. The 0.8 is a rought constant calculated by guess & check, it may be innacurate.
    long tab = maxSize*0.8;
    PARAFORMAT pf;
    pf.cbSize = sizeof(PARAFORMAT);
    pf.dwMask = PFM_TABSTOPS;
    pf.cTabCount = 2;
    pf.rgxTabs[0] = tab + (2 << 24); //make the first tab right-aligned
    pf.rgxTabs[1] = tab + 25;

    //this is to preserve the user's selection and scroll positions when the selection is changed
    int vScroll = GetScrollPos(SB_VERT);
    int hScroll = GetScrollPos(SB_HORZ);
    long spos, epos;
    GetSel(spos, epos);

    //select all the text
    SetSel(0, -1);
    //this call is very important, but I'm not sure why
    ::SendMessage(GetSafeHwnd(), EM_SETTYPOGRAPHYOPTIONS, TO_ADVANCEDTYPOGRAPHY, TO_ADVANCEDTYPOGRAPHY);
    this->SetParaFormat(pf);

    //now reset the user's selection and scroll positions
    SetSel(spos, epos);
    ::SendMessage(GetSafeHwnd(), 
        WM_HSCROLL, 
        (WPARAM) ((hScroll) << 16) + SB_THUMBPOSITION,
        (LPARAM) NULL);
    ::SendMessage(GetSafeHwnd(), 
        WM_VSCROLL, 
        (WPARAM) ((vScroll) << 16) + SB_THUMBPOSITION,
        (LPARAM) NULL);
}

基本的に、この関数が行うことは、最初のタブ ストップを右揃えにして、コントロール内の x 方向の右に設定することです。次に、2 番目のタブ ストップをその少し右側に配置し、左揃えにします。したがって、各行の先頭からクエリ文字列の末尾まで (最初の \t から 2 番目の \t まで) のすべてのテキストは、最初のタブ ストップに対して右に押し出され、残りのすべてのテキストは左に押し出されます。 2 番目のタブ ストップに対して、クエリ文字列がコントロール内のすべての行の間に配置されます。関数の最初の部分は x を見つけ (各行が描画される長さを調べて最大値を取得することにより)、2 番目の部分はタブ ストップを設定します。

ソリューションを提供してくれた ymett に再び感謝します。

于 2011-08-13T23:45:15.950 に答える