Как считать страницы в контроле Richtextbox?

Тема в разделе ".NET", создана пользователем advenedizo, 24 авг 2007.

Наш партнер Genesis Hackspace
  1. advenedizo

    advenedizo Гость

    Здравствуйте.
    Как мне посчитать количество страниц в контроле RichTextBox если учесть, что форматирование по ходу текста может быть различным, а текст может содержать картинки и другие объекты?

    И ещё, в данное время менее важный для меня, но, наверное, более сложный вопрос:
    как можно реализовать визуальное представление многостраничности?
     
  2. mms

    mms Гость

    Элементарно ватсон :blink:

    Код (Text):
            [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);

    [StructLayout(LayoutKind.Sequential)]
    struct SCROLLINFO
    {
    public uint cbSize;
    public uint fMask;
    public int nMin;
    public int nMax;
    public uint nPage;
    public int nPos;
    public int nTrackPos;
    }

    private enum ScrollBarDirection
    {
    SB_HORZ = 0,
    SB_VERT = 1,
    SB_CTL = 2,
    SB_BOTH = 3
    }

    private enum ScrollInfoMask
    {
    SIF_RANGE = 0x1,
    SIF_PAGE = 0x2,
    SIF_POS = 0x4,
    SIF_DISABLENOSCROLL = 0x8,
    SIF_TRACKPOS = 0x10,
    SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS
    }
    Использование:

    Код (Text):
                SCROLLINFO si = new SCROLLINFO();
    si.cbSize = (uint)Marshal.SizeOf( si );
    si.fMask = (int) ScrollInfoMask.SIF_ALL;
    if (GetScrollInfo( richTextBox1.Handle, (int) ScrollBarDirection.SB_VERT, ref si ))
    {

    int pageCount = (int)Math.Ceiling((si.nMax - si.nMin) / (double)si.nPage);
    }
     
  3. advenedizo

    advenedizo Гость

    mms, спасибо большое.

    А нет возможности получить размеры области RichTextBox'а, занятой текстом (или картинками)?

    Допустим, такая задача: нужно определить количество страниц, которые бы занимал текст из выделенного диапазона. Но, это я к примеру.
     
  4. advenedizo

    advenedizo Гость

    Кстати, если использовать предложенный mms вариант, то в случае, когда из текста, состоящего из нескольких страниц, вырезаешь большой кусок, сокращения количества страниц не происходит.
    Я так понимаю, в этом случае необходимо посылать сообщение WM_VSCROLL?

    Как это сделать?
    На какое событие лучше всего?
     
  5. mms

    mms Гость

    <!--QuoteBegin-advenedizo+24:08:2007, 14:07 -->
    <span class="vbquote">(advenedizo @ 24:08:2007, 14:07 )</span><!--QuoteEBegin-->А нет возможности получить размеры области RichTextBox'а, занятой текстом (или картинками)?
    [snapback]76290" rel="nofollow" target="_blank[/snapback]​
    [/quote]

    Не очень понимаю, что имеется ввиду.

    <!--QuoteBegin-advenedizo+24:08:2007, 14:07 -->
    <span class="vbquote">(advenedizo @ 24:08:2007, 14:07 )</span><!--QuoteEBegin-->Допустим, такая задача: нужно определить количество страниц, которые бы занимал текст из выделенного диапазона. Но, это я к примеру.
    [snapback]76290" rel="nofollow" target="_blank[/snapback]​
    [/quote]

    Если шрифт одинаковый, то размеры выбранного текста (без картинок) можно получить при помощи MeasureString. По другому - фиг знает, мулировать поведение ричтекстбокса, либо попытаться получить нужную инфу через рефлекшен.

    <!--QuoteBegin-advenedizo+24:08:2007, 14:23 -->
    <span class="vbquote">(advenedizo @ 24:08:2007, 14:23 )</span><!--QuoteEBegin-->Кстати, если использовать предложенный mms вариант, то в случае, когда из текста, состоящего из нескольких страниц, вырезаешь большой кусок, сокращения количества страниц не происходит.
    [snapback]76294" rel="nofollow" target="_blank[/snapback]​
    [/quote]

    Всё работает, после изменения текста нужно еще раз вызвать функцию считывающую параметры скроллера.
     
  6. advenedizo

    advenedizo Гость

    mms спасибо огромное за ответы.


    Почему MeasureString не подходит, понятно из постановки задачи
    Насчет рефлекшн - что-то никак не пойму, каким образом она может здесь помочь.

    А замарачиваюсь я потому, что по ходу дела может всплыть куча дополнительных требований, с которыми предложенный вариант с GetScrollInfo может не справиться.
    Например, теперь мне нужно определить номер текущей страницы.

    <!--QuoteBegin-mms+24:08:2007, 13:53 -->
    <span class="vbquote">(mms @ 24:08:2007, 13:53 )</span><!--QuoteEBegin-->Всё работает, после изменения текста нужно еще раз вызвать функцию считывающую параметры скроллера.
    [snapback]76254" rel="nofollow" target="_blank[/snapback]​
    [/quote]

    Работает, но не всегда корректно.
    К примеру, если вырезать весь текст, значение количества страниц не измениться.
    (Вызов фунции по событию TextChanged)
     
  7. mms

    mms Гость

    <!--QuoteBegin-advenedizo+28:08:2007, 07:58 -->
    <span class="vbquote">(advenedizo @ 28:08:2007, 07:58 )</span><!--QuoteEBegin-->А замарачиваюсь я потому, что по ходу дела может всплыть куча дополнительных требований, с которыми предложенный вариант с GetScrollInfo может не справиться.
    Например, теперь мне нужно определить номер текущей страницы.
    Работает, но не всегда корректно.
    К примеру, если вырезать весь текст, значение количества страниц не измениться.
    (Вызов фунции по событию TextChanged)[/quote]

    Чутка расширим функционал и вуаля:

    Native декларации:

    Код (Text):
            [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);

    [StructLayout(LayoutKind.Sequential)]
    struct SCROLLINFO
    {
    public uint cbSize;
    public uint fMask;
    public int nMin;
    public int nMax;
    public uint nPage;
    public int nPos;
    public int nTrackPos;
    }

    private enum ScrollBarDirection
    {
    SB_HORZ = 0,
    SB_VERT = 1,
    SB_CTL = 2,
    SB_BOTH = 3
    }

    private enum ScrollInfoMask
    {
    SIF_RANGE = 0x1,
    SIF_PAGE = 0x2,
    SIF_POS = 0x4,
    SIF_DISABLENOSCROLL = 0x8,
    SIF_TRACKPOS = 0x10,
    SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS
    }

    [DllImport( "user32.dll", SetLastError=true, EntryPoint="GetScrollBarInfo")]
    private static extern int GetScrollBarInfo(IntPtr hWnd, uint idObject, ref SCROLLBARINFO psbi);

    [StructLayout(LayoutKind.Sequential)]
    public struct SCROLLBARINFO
    {
    public int cbSize;
    public Rectangle rcScrollBar;
    public int dxyLineButton;
    public int xyThumbTop;
    public int xyThumbBottom;
    public int reserved;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=6)]
    public int[] rgstate;
    }

    private const uint OBJID_HSCROLL = 0xFFFFFFFA;
    private const uint OBJID_VSCROLL = 0xFFFFFFFB;
    private const uint OBJID_CLIENT = 0xFFFFFFFC;

    private const uint STATE_SYSTEM_UNAVAILABLE = 0x00000001;
    Использование:

    Код (Text):
                SCROLLBARINFO psbi = new SCROLLBARINFO();
    psbi.cbSize = Marshal.SizeOf(psbi);

    if (GetScrollBarInfo(richTextBox1.Handle, OBJID_VSCROLL, ref psbi) != 0)
    {
    int pageCount = 0;
    double curPage = 0;
    if (psbi.rgstate[0] == STATE_SYSTEM_UNAVAILABLE)
    {
    pageCount = 0;
    curPage = 0;
    }
    else
    {
    SCROLLINFO si = new SCROLLINFO();
    si.cbSize = (uint)Marshal.SizeOf( si );
    si.fMask = (int) ScrollInfoMask.SIF_ALL;

    if (GetScrollInfo( richTextBox1.Handle, (int) ScrollBarDirection.SB_VERT, ref si ))
    {
    pageCount = (int)Math.Ceiling((si.nMax - si.nMin) / (double)si.nPage);
    curPage = si.nPos / (double)si.nPage + 1;
    }
    }
    }
    pageCount - количество страниц.
    curPage - текущая страница, дабл, потому что может быть отскролирована только часть страницы.
     
  8. advenedizo

    advenedizo Гость

    Спасибо
     
Загрузка...

Поделиться этой страницей