2014-12-20 41 views
0

我使用GetTextExtentPoint32W獲取MS Excel 2010中單元格中文本的寬度。使用ActiveCell.Width獲取單元格寬度。然後比較這兩個寬度以確定文本是否適合單元格或者延伸到單元格之外。從視覺上看,即使文本完全適合單元格,該方法返回的文本寬度也大於單元格寬度。另外,當我增加字體大小時,實際文本寬度與方法返回的寬度之間的差異增大。 以下是用於實現結果的源代碼的一部分。請幫我解決這個錯誤。在MS Excel中,由GetTextExtentPoint32W返回的單元格中文本的文本寬度大於實際寬度

hDC = ctypes.windll.user32.GetDC(self.windowHandle) 
    tempBMP = ctypes.windll.gdi32.CreateCompatibleBitmap(hDC, 1, 1) 
    hBMP = ctypes.windll.gdi32.SelectObject(hDC, tempBMP) 

    iFontSize = self.excelCellObject.Font.Size 
    deviceCaps = ctypes.windll.gdi32.GetDeviceCaps(hDC, 90) 
    iFontSize = int(iFontSize) 
    iFontSize = ctypes.c_int(iFontSize) 
    iFontSize = ctypes.windll.kernel32.MulDiv(iFontSize, deviceCaps, 72) 
    iFontSize = iFontSize * -1 
    iFontWeight = 700 if self.excelCellObject.Font.Bold else 400 

    sFontName = self.excelCellObject.Font.Name 
    sFontItalic = self.excelCellObject.Font.Italic 
    sFontUnderline = True if self.excelCellObject.Font.Underline else False 
    sFontStrikeThrough = self.excelCellObject.Font.Strikethrough 

    #Create a font object with the correct size, weight and style 
    hFont = ctypes.windll.gdi32.CreateFontW(iFontSize, 
              0, 0, 0, 
              iFontWeight, 
              sFontItalic, 
              sFontUnderline, 
              sFontStrikeThrough, 
              False, False, False, 
              False, False, 
              sFontName) 

    #Load the font into the device context, storing the original font object 
    hOldFont = ctypes.windll.gdi32.SelectObject(hDC, hFont) 
    sText = self.excelCellObject.Text 
    log.io("\nText \t"+sText+"\n") 
    textLength = len(sText) 

    class structText(ctypes.Structure): 
     _fields_ = [("width", ctypes.c_int), 
        ("height",ctypes.c_int)] 

    StructText = structText() 
    getTextExtentPoint = ctypes.windll.gdi32.GetTextExtentPoint32W 
    getTextExtentPoint.argtypes = [ctypes.c_void_p, 
            ctypes.c_char_p, 
            ctypes.c_int, 
            ctypes.POINTER(structText)] 
    getTextExtentPoint.restype = ctypes.c_int 

    #Get the text dimensions 
    a = ctypes.windll.gdi32.GetTextExtentPoint32W(hDC, 
                sText, 
                textLength, 
                ctypes.byref(StructText)) 

    #Delete the font object we created 
    a = ctypes.windll.gdi32.DeleteObject(hFont) 
    a = ctypes.windll.gdi32.DeleteObject(tempBMP) 

    #Release the device context 
    a = ctypes.windll.user32.ReleaseDC(self.windowHandle, hDC) 
    textWidth = StructText.width 
    cellWidth = self.excelCellObject.Width 

謝謝。

+0

要麼使用'GetTextExtentPoint32A'與ANSI字符串,要麼解碼爲'unicode'使用'GetTextExtentPoint32W'。對於後者,在'argtypes'中使用'c_wchar_p'。 – eryksun

+0

感謝@eryksun讓這篇文章可讀。我提出了你所建議的更改。這讓我更接近最終解決方案。我會很快發佈它。 –

回答

0

我不使用Python或Excel 2010,因此無法對您當前的方法發表評論。不過,我也遇到過類似的問題。我希望以下幾點會有所幫助。


背景

如果你將鼠標懸停在一個Excel列的右邊界並按住鼠標左鍵,你會得到的格式顯示:「寬度:n.nn(毫米像素) 」。

爲ColumnWidth屬性的幫助,說:

一列寬的單位等於一個字符在 普通樣式的寬度。對於比例字體,使用字符寬度0 (零)。

使用Width屬性返回點的寬度。

據我所知,「正常風格」是指工作簿創建時的標準字體名稱和大小。更改現有工作簿的標準字體名稱和大小似乎沒有任何作用。更改工作表的字體名稱和大小不起作用。

兩個示例顯示用於標準寬度柱有:

For Arial 10   Width: 8.43 (64 pixels) 
For Tahoma 10.5  Width: 8.38 (72 pixels) 

我創建零的字符串,並試圖測量多少取決於列的寬度是可見的。我發現我可以看到的零點數與匹配顯示的值相當好,例如主觀測量。

使用VBA時,列或單元格的ColumnWidth屬性設置或返回字符寬度。

使用VBA,列或單元格的只讀寬度屬性返回.75 *寬度(以像素爲單位)。

上述信息的意義在於,從Excel中獲取的寬度值對於使用的字體不一定是正確的。


我的問題和解決方案,我發現

我的問題是,我是合併單元格,並用文本填充。儘管Excel將調整行的高度,以使未合併單元格內的文本可見,但對合並單元格不會這樣做。我嘗試了許多技術,包括微軟的.Net,文本渲染例程,但沒有成功。我試過的任何東西都不會模仿Excel的系統來確定文本的寬度。

我最終成功使用的技術包括在右側和下方使用所有使用過的細胞進行實驗。我調整了實驗單元格列的寬度以匹配合並單元格的合併寬度,並從我想要的高度單元格中複製格式化的值。由於實驗單元未被合併,Excel會根據情況調整高度。然後我確定源行至少是這個高度。

這種技術的關鍵特點是我沒有試圖模擬Excel的系統來確定文本的寬度;我正在使用Excel的系統。

您需要爲實驗單元嘗試不同的列寬。我將從源列的當前寬度開始。如果行高與單行匹配,則源列的寬度已經足夠。如果行高度大於單行的高度,我會增加列寬,直到行高與單行匹配,然後調整源列的寬度以匹配。如果以最大值(以字符或Python的文本寬度)開頭,那麼您可能會在第一次嘗試時獲得源列寬度正確的值,從而避免以後進行調整。

相關問題