Получить и установить позиции прокрутки элемента C # Forms RichTextBox [duplicate]

Что вы хотите сделать, в основном, превратить NSAttributedString в NSMutableAttributedString.

let attributedT = // ... attributed string
let mutableT = NSMutableAttributedString(attributedString:attributedT)

Теперь вы можете вызвать addAttributes , чтобы применить атрибуты, такие как другой шрифт, в любом желаемом диапазоне, например, все это.

Однако, к сожалению, шрифт без символической черты, такой как курсив, представляет собой другой шрифт из шрифта с этим символическим признаком. Поэтому вам понадобится утилита, которая копирует существующие символические черты из шрифта и применяет их к другому шрифту:

func applyTraitsFromFont(_ f1: UIFont, to f2: UIFont) -> UIFont? {
    let t = f1.fontDescriptor.symbolicTraits
    if let fd = f2.fontDescriptor.withSymbolicTraits(t) {
        return UIFont.init(descriptor: fd, size: 0)
    }
    return nil
}

Хорошо, поэтому, вооружившись этой утилитой, давайте попробуем. Я начну с простого HTML-кода и преобразую его в атрибутную строку, как вы это делаете:

let html = "

Hello world, hello

" let data = html.data(using: .utf8)! let att = try! NSAttributedString.init( data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) let matt = NSMutableAttributedString(attributedString:att)

Как вы можете видеть, я перешел в NSMutableAttributedString, как я вам посоветовал. Теперь я буду циклически выполнять стили в терминах шрифта, изменяясь на другой шрифт, используя мою утилиту для применения существующих признаков:

matt.enumerateAttribute(
    NSFontAttributeName,
    in:NSMakeRange(0,matt.length),
    options:.longestEffectiveRangeNotRequired) { value, range, stop in
        let f1 = value as! UIFont
        let f2 = UIFont(name:"Georgia", size:20)!
        if let f3 = applyTraitsFromFont(f1, to:f2) {
            matt.addAttribute(
                NSFontAttributeName, value:f3, range:range)
        }
    }

Вот результат:

Очевидно, вы могли бы настроить эту процедуру еще более сложной, в зависимости от ваших потребностей в дизайне.

15
задан Donut 1 December 2009 в 17:29
поделиться

4 ответа

Я сделал это для небольшого проекта некоторое время назад, и вот упрощенное решение, которое я нашел.

Создайте новый элемент управления путем подкласса RichTextBox:

   public class SynchronizedScrollRichTextBox : System.Windows.Forms.RichTextBox
    {
        public event vScrollEventHandler vScroll;
        public delegate void vScrollEventHandler(System.Windows.Forms.Message message);

        public const int WM_VSCROLL = 0x115;

        protected override void WndProc(ref System.Windows.Forms.Message msg) {
            if (msg.Msg == WM_VSCROLL) {
                if (vScroll != null) {
                    vScroll(msg);
                }
            }
            base.WndProc(ref msg);
        }

        public void PubWndProc(ref System.Windows.Forms.Message msg) {
            base.WndProc(ref msg);
        }
    }     

Добавьте новый элемент управления в свою форму и для каждого элемента управления явным образом уведомите другие экземпляры элемента управления о том, что его позиция vScroll изменилась , Что-то вроде этого:

private void scrollSyncTxtBox1_vScroll(Message msg) {
    msg.HWnd = scrollSyncTxtBox2.Handle;
    scrollSyncTxtBox2.PubWndProc(ref msg);
}

Я думаю, что этот код имеет проблемы, если все «связанные» элементы управления не имеют одинакового количества отображаемых строк.

15
ответ дан Jay Riggs 21 August 2018 в 08:25
поделиться
  • 1
    Этот метод отлично работает для прокрутки, перемещая полосу прокрутки. Но полосы прокрутки не синхронизируются, когда (1) прокручивается с колесиком мыши (2), прокручиваемым клавишами page down или page up - прокруткой, нажимая клавиши со стрелками – twnaing 30 May 2011 в 04:54
  • 2
    @Jay riggs 'System.Windows.Forms.RichTextBox' не содержит определения для 'PubWndProc' и никакого метода расширения 'PubWndProc', принимающего первый аргумент типа 'System.Windows.Forms.RichTextBox', может быть найден (вам не хватает директива использования или ссылка на сборку?) – Pomster 6 June 2012 в 07:59

Вариант подкласса Jay можно найти в сообщении Джозефа Кингри здесь: Синхронизация многострочных позиций текстового поля в C # . Подход Джозефа также подклассы, но не требует обработчика события _VScroll. Я использовал этот подход, чтобы выполнить 3-стороннее связывание между 3-мя блоками и добавленным WM_HSCROLL.

1
ответ дан Community 21 August 2018 в 08:25
поделиться

Спасибо Джей за ваш ответ; после еще нескольких поисков я нашел метод, описанный здесь здесь .


Сначала объявим следующие перечисления:

public enum ScrollBarType : uint {
   SbHorz = 0,
   SbVert = 1,
   SbCtl = 2,
   SbBoth = 3
 }

public enum Message : uint {
   WM_VSCROLL = 0x0115
}

public enum ScrollBarCommands : uint {
   SB_THUMBPOSITION = 4
}

Затем добавьте внешние ссылки на GetScrollPos и SendMessage .

[DllImport( "User32.dll" )]
public extern static int GetScrollPos( IntPtr hWnd, int nBar );

[DllImport( "User32.dll" )]
public extern static int SendMessage( IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam );

Наконец, добавьте обработчик событий для события VScroll соответствующего RichTextBox :

private void myRichTextBox1_VScroll( object sender, EventArgs e )
{
   int nPos = GetScrollPos( richTextBox1.Handle, (int)ScrollBarType.SbVert );
   nPos <<= 16;
   uint wParam = (uint)ScrollBarCommands.SB_THUMBPOSITION | (uint)nPos;
   SendMessage( richTextBox2.Handle, (int)Message.WM_VSCROLL, new IntPtr( wParam ), new IntPtr( 0 ) );
}

В этом случае положение вертикальной прокрутки richTextBox2 будет синхронизировано с richTextBox1.

19
ответ дан Donut 21 August 2018 в 08:25
поделиться
  • 1
    Отличное резюме. Сэкономил много времени. Спасибо! – Aditya Bokade 15 August 2012 в 12:33
  • 2
    какой будет шестнадцатеричный код для WM_HSCROLL? – Logerfo 9 November 2016 в 19:19

[Visual Studio C # 2010 Express, v10.0.30319 на Windows 7 64-битной установке]

Я использовал решение Donut выше, но обнаружил проблему при прокрутке до конца RichTextBoxes, которые содержат много линий.

Если результат GetScrollPos() равен >0x7FFF, тогда, когда nPos сдвинут, верхний бит установлен. При создании IntPtr с результирующей переменной wParam произойдет сбой OverflowException. Вы можете легко проверить это следующим образом (вторая строка не сработает):

    IntPtr ip = new IntPtr(0x7FFF0000);
    IntPtr ip2 = new IntPtr(0x80000000);

Версия SendMessage(), которая использует UIntPtr, окажется решением, но я не мог получить что работать. Итак, я использую следующее:

    [DllImport("User32.dll")]
    public extern static int SendMessage(IntPtr hWnd, uint msg, UInt32 wParam, UInt32 lParam);

Это должно быть хорошо до 0xffff, но после этого произойдет сбой. Я еще не испытал результат >0xffff из GetScrollPos() и предположил, что User32.dll вряд ли будет иметь 64-битную версию SendCommand(), но любые решения этой проблемы будут весьма полезны.

3
ответ дан lesmana 21 August 2018 в 08:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: