2009-12-13 65 views
1

我已經擴展了RichTextBox控件來實現原生RichEdit類中提供的許多缺少的功能。RichTextBox:如何確定文本是否超出控件邊界?

我運行到哪裏,如果控制設置換行到窗口或換到打印機的水平滾動條出現,即使它不應該當控制調整大小的問題。

騎自行車的換行無法比擬和背部可能會解決問題,但包裹到打印機時,可以相對慢(即:速度過慢對每一個Resize事件調用)。

這裏是我的換行代碼:

private void ChangeWordWrap(WordWrap wordWrap) 
    { 
     switch (wordWrap) 
     { 
      case WordWrap.NoWrap: 
       { 
        User32.SendMessage(_RichTextBox.Handle, ApiConstants.EM_SETTARGETDEVICE, 0, 1); 
        break;       
       } 
      case WordWrap.WrapToPrintDocument: 
       { 
        using (Graphics g = PrintDocument.PrinterSettings.CreateMeasurementGraphics(PrintDocument.DefaultPageSettings)) 
        { 
         int lParam = ConvertEx.HundredthInchToTwips((PrintDocument.DefaultPageSettings.Bounds.Width - PrintDocument.DefaultPageSettings.Margins.Left - PrintDocument.DefaultPageSettings.Margins.Right)); 
         IntPtr wParam = g.GetHdc(); 
         User32.SendMessage(_RichTextBox.Handle, ApiConstants.EM_SETTARGETDEVICE, wParam, lParam); 
         g.ReleaseHdc(); 
        } 
        break;             
       } 
      case WordWrap.WrapToControl: 
       { 
        User32.SendMessage(_RichTextBox.Handle, ApiConstants.EM_SETTARGETDEVICE, 0, 0); 
        break; 
       } 
     } 
    } 

Originially我想這個問題可能與這樣的事實,我釋放了圖形處理,但是當我在包裝的控制和無柄也出現問題是必要的。

添加截圖:

正確的行爲:

alt text http://www.charltonfamily.net/temp/RTB_EM_SETTARGETDEVICE/WrapToPrinter_Correct_Horizontal_Scrollbar.png

不正確的行爲(調整形式非常後小幅):

alt text http://www.charltonfamily.net/temp/RTB_EM_SETTARGETDEVICE/WrapToPrinter_Inappropriate_Horizontal_Scrollbar.png

環繞到窗口/無包裝代碼來自評論在http://msdn.microsoft.com/en-us/library/bb774282(VS.85).aspx

調用:: SendMessage消息(HWND,EM_SETTARGETDEVICE,NULL,0),將文本換行到窗口,並:: SendMessage消息(HWND,EM_SETTARGETDEVICE,NULL ,1)將完全禁用自動換行。我不確定這是否記錄在其他地方。

我的P/Invoke:

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

相關常量:

public const int WM_USER = 0x400; 
    public const int EM_SETTARGETDEVICE = (WM_USER + 72); 

編輯:

我一直在研究這個更多,我相信.NET RichTextBox控件當控件調整大小時,可能會發送帶有錯誤值的SetScrollRange()。這是有道理的,因爲它不一定知道EM_SETTARGETDEVICE消息。

我可能在調整大小後執行SetScrollRange()或類似的東西,但我的問題是我不知道什麼是正確的值,或者我怎麼可以去弄清楚。

我注意到另一件事是,當這個問題是存在的,我可以調整控件的大小實際上換行。在這一點上,滾動條返回到功能狀態,我可以調整大小,直到單詞換行循環到無和返回。

編輯:(也是我下面的非功能性的回答一些更詳細)

看起來EM_GETRECT是不是我真正想要的,因爲它的大小變化的時候,控制大小的變化。這裏的MSDN描述:

EM_GETRECT消息

獲取編輯控件的格式化矩形。格式化矩形是控件繪製文本的限制矩形。限制矩形與編輯控制窗口的大小無關。您可以將此消息發送到編輯控件或豐富的編輯控件。

我最初的理解是,這是整個文本的矩形,我可以確定客戶端窗口是否小於格式化矩形,因此應該顯示滾動條。

看起來這個格式化矩形的真正目的是使文本顯示在小於編輯控件(即:邊距)的區域中。

新問題:

那麼,有沒有一個矩形,這就是我想EM_GETRECT會給我?一個矩形會告訴我文本有多寬(包括屏幕上的部分)是多少?例如,如果我有一個400px的控件和一行800px長的文本,我想獲得800px的值,所以我可以比較它來控制寬度並顯示/不顯示滾動條。

其實我不在乎關閉控制文本的長度,因爲我關心的知道IF文本超出了控件的範圍。

感謝所有幫助到目前爲止。

+0

我的屏幕截圖不能很好地表現出來,但除了顯示在標尺欄中的RTF縮進外,還有一個指定給RichEdit控件的打印機頁面寬度。 – 2009-12-13 15:42:34

回答

0

我有些工作,但這不是我真正想要的。

我真正想要的是讓RichTextBox做我想做的事情。相反,我讓RichTextBox做它想做的事情,然後在事實之後嘗試修復它。這是一個健談的解決方案,有時會導致滾動條閃爍。

下面是我在做什麼:

SCROLLINFO scrollinfo = new SCROLLINFO(); 
scrollinfo.cbSize = Marshal.SizeOf(scrollinfo); 
scrollinfo.fMask = ApiConstants.SIF_ALL; 
bool flag1 = User32.GetScrollInfo(_RichTextBox.Handle, ApiConstants.SB_HORZ, ref scrollinfo); 

Logging.LogMessage("Resize - ScrollInfo: Max: " + scrollinfo.nMax + " Min: " + scrollinfo.nMin + " Page: " + scrollinfo.nPage + " Pos: " + scrollinfo.nPos + " TrackPos: " + scrollinfo.nTrackPos + " || RichtTextBox.RightMargin == " + _RichTextBox.RightMargin + " || RichTextBox.WordWrap == " + WordWrap + "/" + _RichTextBox.WordWrap + " Size: " + Size + " ClientRectangle: " + _RichTextBox.ClientSize); 

switch (WordWrap) 
{ 
    case WordWrap.WrapToControl: 
    { 
     if (scrollinfo.nMax > _RichTextBox.ClientSize.Width) 
     { 
      User32.ShowScrollBar(_RichTextBox.Handle, ApiConstants.SB_HORZ, false); 
     } 
     break; 
    } 
    case WordWrap.WrapToPrintDocument: 
    { 
     if (scrollinfo.nMax > _PrintableWidth) 
     { 
      User32.ShowScrollBar(_RichTextBox.Handle, ApiConstants.SB_HORZ, false); 
     } 
     break; 
    } 
} 

WordWrap.WrapToControl條件的邏輯被打破,我不知道如何解決它。問題是,在錯誤情況下,最大滾動大於ClientSize。但是,當文本實際在屏幕上運行時(考慮左縮進),最大滾動也大於ClientSize。

我想我可以通過使用EM_GETRECT消息來解決這個問題,但我仍然需要做更多的測試。有可能EM_GETRECT解決方案也適用於WrapToPrintDocument條件,但是如果它確實爲什麼RichTextBox沒有這樣做?真的希望我能找到RichTextBox從SCROLLINFO參數獲取的位置,因爲那樣我就可以讓RichTextBox控件做我想做的事,而不需要第二個「修復」消息。

注:我不需要情況下顯示滾動因爲RichTextBox的處理這部分罰款後,我隱藏它(嘆息

編輯:

看起來EM_GETRECT不我真正想要的是因爲當控件大小發生變化時它的大小發生了變化。這裏的MSDN描述:

EM_GETRECT消息 獲取編輯控件的格式化矩形。格式化矩形是控件繪製文本的限制矩形。限制矩形與編輯控制窗口的大小無關。您可以將此消息發送到編輯控件或豐富的編輯控件。

我最初的理解是,這是整個文本的矩形,從中我可以確定客戶端窗口是否更小,格式化矩形,因此應該顯示滾動條。

看起來這個格式化矩形的真正目的是使文本顯示在小於編輯控件(即:邊距)的區域中。

新問題:

那麼,有沒有一個矩形,這就是我想EM_GETRECT會給我?一個矩形會告訴我文本有多寬(包括屏幕上的部分)是多少?例如,如果我有一個400px的控件和一行800px長的文本,我想獲得800px的值,所以我可以比較它來控制寬度並顯示/不顯示滾動條。

感謝所有幫助到目前爲止。

2

我還沒有試過你的代碼,沒有P/Invoke聲明就不容易運行。儘管您的SendMessage的LPARAM參數聲明看起來不正確,但它應該是IntPtr。爲WPARAM傳遞0不應該編譯,不知道你做了什麼。

一定要檢查SendMessage()的返回值,如果RichEdit對您的參數不滿意,它將返回IntPtr.Zero。在SDK文檔中沒有提到爲設備上下文句柄傳遞0作爲可接受的值,您可能需要爲屏幕傳遞HDC。輕鬆從Control.CreateGraphics()獲取。

我也不清楚爲什麼你不想要水平滾動條出現。我希望當你切換到打印機所見即所得模式時你會看到一個。

+0

sendmessage的返回值很好,wordwrap可以正確切換。當控件在此之後調整大小時,問題就會顯現出來。 就水平滾動條而言,如果它存在但是問題在於它處於非功能狀態(請參見屏幕截圖),那麼我很好。 我也有一個p/invoke簽名需要一個IntPtr的lParam,但並不認爲這是必要的,因爲我只需要傳遞一個int值到消息我不認爲IntPtr是必要的。 – 2009-12-13 15:38:20

+0

「非功能性」我的意思是:當文本不超出控制範圍時,滾動條處於活動狀態。滾動按鈕的寬度和欄的長度處於一種狀態,表示文本延伸得遠遠超出控件的邊緣。移動滾動按鈕移動「文本內容」,然後將其位置重置到左側。 – 2009-12-13 15:40:05

0

你試過the EM_SHOWSCROLLBAR Message

或者,您可以在調整大小之前嘗試 WM_SETREDRAW(0),並在WM_SETREDRAW(1)完成之後嘗試。

+0

是的,EM_SCROLLBAR消息不會改變任何東西(假設當ScrollBars屬性設置爲Both時,RichTextBox已經發送了這個消息 – 2009-12-15 08:09:02

+0

而WM_SETREDRAW也沒有改變任何東西。 – 2009-12-15 08:14:34