Название приложения отрезано в VB6 - PullRequest
4 голосов
/ 27 сентября 2008

Платформа: Windows XP Платформа разработки: VB6

При попытке установить заголовок приложения в диалоговом окне «Свойства проекта» на вкладке «Создать» кажется, что заголовок молча обрезается на определенное количество символов. Также пробовал это через свойство App.Title, и, похоже, страдает от той же проблемы. Меня это не волнует, но отдел контроля качества настаивает на том, что нам нужно отобразить весь заголовок.

У кого-нибудь есть обходной путь или исправление для этого?


Редактировать: Для тех, кто ответил примерно на 40 символов, это то, что я как бы подозревал - отсюда мой вопрос о возможном обходном пути :-).

На самом деле я отправил этот вопрос, чтобы попытаться помочь коллеге-разработчику, поэтому, когда я увижу ее в понедельник, я укажу ей все ваши отличные предложения и посмотрю, поможет ли кто-нибудь из них исправить это. Я знаю, что по некоторым причинам некоторые диалоговые окна, отображаемые приложением, похоже, выбирают строку из параметра App.Title, поэтому она спросила меня об ограничении длины строки.

Я просто хотел бы найти что-то определенное от Microsoft (например, какую-то заметку в КБ), чтобы она могла показать это нашему отделу контроля качества, чтобы они поняли, что это просто ограничение VB.

Ответы [ 5 ]

4 голосов
/ 27 сентября 2008

Функция MsgBox принимает параметр для заголовка. Если вы не хотите изменять каждый отдельный вызов функции MsgBox, вы можете «переопределить» поведение по умолчанию:

Function MsgBox(Prompt, Optional Buttons As VbMsgBoxStyle = vbOKOnly, Optional Title, Optional HelpFile, Optional Context) As VbMsgBoxResult
    If IsMissing(Title) Then Title = String(40, "x") & "abc"
    MsgBox = Interaction.MsgBox(Prompt, Buttons, Title, HelpFile, Context)
End Function

Редактировать: Как отмечает Майк Спросс: Это скрывает только обычную функцию MsgBox. Если вы хотите получить доступ к своему пользовательскому MsgBox из другого проекта, вам придется его квалифицировать.

3 голосов
/ 27 сентября 2008

Я только что создал стандартный EXE-проект в IDE и набирал текст в поле заголовка приложения на вкладке «Свойства проекта», пока не заполнил это поле. Из этого быстрого теста видно, что App.Title ограничен 40 символами. Затем я попробовал это в коде, поместив следующий код в форму по умолчанию (Form1), созданную для проекта:

Private Sub Form_Load()
    App.Title = String(41, "X")
    MsgBox Len(App.Title)
End Sub

Этот быстрый тест подтверждает ограничение в 40 символов, поскольку MsgBox отображает 40, хотя код пытается установить для App.Title строку из 41 символа.

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

Dim nTitleBarTextWidth As Long
Dim nNewWidth As Long

Me.Caption = "My really really really really really long app title here"

' Get titlebar text width (somehow) '
nTitleBarTextWidth = GetTitleBarTextWidth()

' Compute the new width for the Form such that the title will fit within it '
' (May have to add a constant to this to make sure the title fits correctly) '
nNewWidth = Me.ScaleX(nTitleBarTextWidth, vbPixels, Me.ScaleMode)

' If the new width is bigger than the forms current size, use the new width '
If nNewWidth > Me.Width Then
    Form.Width = nNewWidth
End If
2 голосов
/ 27 сентября 2008

Одно решение с использованием Windows API


Отказ от ответственности : ИМХО это кажется излишним просто для того, чтобы выполнить требование, изложенное в вопросе, но в духе (надеюсь) полного ответа на проблему здесь ничего не происходит ...

Вот рабочая версия, которую я придумал, немного посмотрев в MSDN, пока, наконец, не наткнулся на статью о vbAccelerator, которая заставила мои колеса вращаться.

  • См. Страницу vbAccelerator для исходной статьи (напрямую не связанной с вопросом, но мне было достаточно, чтобы сформулировать ответ)

Основная предпосылка заключается в том, чтобы сначала вычислить ширину текста заголовка формы, а затем использовать GetSystemMetrics , чтобы получить ширину различных битов окна, таких как граница и ширина рамки окна, ширина кнопок «Свернуть», «Развернуть» и «Закрыть» и т. д. (я разделил их на их собственные функции для удобства чтения / ясности). Нам нужно учесть эти части окна, чтобы вычислить точную новую ширину формы.

Чтобы точно рассчитать ширину («экстент») заголовка формы, нам нужно получить системный шрифт заголовка, следовательно, SystemParametersInfo и CreateFontIndirect и связанные с ними качества .

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

Я только кратко протестировал, но, кажется, работает нормально. Однако, поскольку он использует функции Windows API, вы можете проявлять осторожность, особенно потому, что он копирует память. Я также не добавил надежную обработку ошибок.

Кстати, если у кого-то есть более чистый и менее сложный способ сделать это, или если я что-то пропустил в своем собственном коде, пожалуйста, дайте мне знать.

Чтобы попробовать, вставьте следующий код в новый модуль

Option Explicit

Private Type SIZE
    cx As Long
    cy As Long
End Type

Private Const LF_FACESIZE = 32

'NMLOGFONT: This declaration came from vbAccelerator (here is what he says about it):'
'                                                                  '
' For some bizarre reason, maybe to do with byte                   '
' alignment, the LOGFONT structure we must apply                   '
' to NONCLIENTMETRICS seems to require an LF_FACESIZE              '
' 4 bytes smaller than normal:                                     '

Private Type NMLOGFONT
   lfHeight As Long
   lfWidth As Long
   lfEscapement As Long
   lfOrientation As Long
   lfWeight As Long
   lfItalic As Byte
   lfUnderline As Byte
   lfStrikeOut As Byte
   lfCharSet As Byte
   lfOutPrecision As Byte
   lfClipPrecision As Byte
   lfQuality As Byte
   lfPitchAndFamily As Byte
   lfFaceName(LF_FACESIZE - 4) As Byte
End Type

Private Type LOGFONT
   lfHeight As Long
   lfWidth As Long
   lfEscapement As Long
   lfOrientation As Long
   lfWeight As Long
   lfItalic As Byte
   lfUnderline As Byte
   lfStrikeOut As Byte
   lfCharSet As Byte
   lfOutPrecision As Byte
   lfClipPrecision As Byte
   lfQuality As Byte
   lfPitchAndFamily As Byte
   lfFaceName(LF_FACESIZE) As Byte
End Type

Private Type NONCLIENTMETRICS
   cbSize As Long
   iBorderWidth As Long
   iScrollWidth As Long
   iScrollHeight As Long
   iCaptionWidth As Long
   iCaptionHeight As Long
   lfCaptionFont As NMLOGFONT
   iSMCaptionWidth As Long
   iSMCaptionHeight As Long
   lfSMCaptionFont As NMLOGFONT
   iMenuWidth As Long
   iMenuHeight As Long
   lfMenuFont As NMLOGFONT
   lfStatusFont As NMLOGFONT
   lfMessageFont As NMLOGFONT
End Type

Private Enum SystemMetrics
    SM_CXBORDER = 5
    SM_CXDLGFRAME = 7
    SM_CXFRAME = 32
    SM_CXSCREEN = 0
    SM_CXICON = 11
    SM_CXICONSPACING = 38
    SM_CXSIZE = 30
    SM_CXEDGE = 45
    SM_CXSMICON = 49
    SM_CXSMSIZE = 52
End Enum

Private Const SPI_GETNONCLIENTMETRICS = 41
Private Const SPI_SETNONCLIENTMETRICS = 42

Private Declare Function GetTextExtentPoint32 Lib "gdi32" Alias "GetTextExtentPoint32A" _
    (ByVal hdc As Long, _
     ByVal lpszString As String, _
     ByVal cbString As Long, _
     lpSize As SIZE) As Long

Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As SystemMetrics) As Long

Private Declare Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" ( _
   ByVal uAction As Long, _
   ByVal uParam As Long, _
   lpvParam As Any, _
   ByVal fuWinIni As Long) As Long

Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Function GetCaptionTextWidth(ByVal frm As Form) As Long

    '-----------------------------------------------'
    ' This function does the following:             '
    '                                               '
    '   1. Get the font used for the forms caption  '
    '   2. Call GetTextExtent32 to get the width in '
    '      pixels of the forms caption              '
    '   3. Convert the width from pixels into       '
    '      the scaling mode being used by the form  '
    '                                               '
    '-----------------------------------------------'

    Dim sz As SIZE
    Dim hOldFont As Long
    Dim hCaptionFont As Long
    Dim CaptionFont As LOGFONT
    Dim ncm As NONCLIENTMETRICS

    ncm.cbSize = LenB(ncm)

    If SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, ncm, 0) = 0 Then
        ' What should we do if we the call fails? Change as needed for your app,'
        ' but this call is unlikely to fail anyway'
        Exit Function
    End If

    CopyMemory CaptionFont, ncm.lfCaptionFont, LenB(CaptionFont)

    hCaptionFont = CreateFontIndirect(CaptionFont)
    hOldFont = SelectObject(frm.hdc, hCaptionFont)

    GetTextExtentPoint32 frm.hdc, frm.Caption, Len(frm.Caption), sz
    GetCaptionTextWidth = frm.ScaleX(sz.cx, vbPixels, frm.ScaleMode)

    'clean up, otherwise bad things will happen...'
    DeleteObject (SelectObject(frm.hdc, hOldFont))

End Function

Private Function GetControlBoxWidth(ByVal frm As Form) As Long

    Dim nButtonWidth As Long
    Dim nButtonCount As Long
    Dim nFinalWidth As Long

    If frm.ControlBox Then

        nButtonCount = 1                            'close button is always present'
        nButtonWidth = GetSystemMetrics(SM_CXSIZE)  'get width of a single button in the titlebar'

        ' account for min and max buttons if they are visible'
        If frm.MinButton Then nButtonCount = nButtonCount + 1
        If frm.MaxButton Then nButtonCount = nButtonCount + 1

        nFinalWidth = nButtonWidth * nButtonCount

    End If

    'convert to whatever scale the form is using'
    GetControlBoxWidth = frm.ScaleX(nFinalWidth, vbPixels, frm.ScaleMode)

End Function

Private Function GetIconWidth(ByVal frm As Form) As Long

    Dim nFinalWidth As Long

    If frm.ControlBox Then

        Select Case frm.BorderStyle

            Case vbFixedSingle, vbFixedDialog, vbSizable:
                'we have an icon, gets its width'
                nFinalWidth = GetSystemMetrics(SM_CXSMICON)
            Case Else:
                'no icon present, so report zero width'
                nFinalWidth = 0

        End Select

    End If

    'convert to whatever scale the form is using'
    GetIconWidth = frm.ScaleX(nFinalWidth, vbPixels, frm.ScaleMode)

End Function

Private Function GetFrameWidth(ByVal frm As Form) As Long

    Dim nFinalWidth As Long

    If frm.ControlBox Then

        Select Case frm.BorderStyle

            Case vbFixedSingle, vbFixedDialog:
                nFinalWidth = GetSystemMetrics(SM_CXDLGFRAME)
            Case vbSizable:
                nFinalWidth = GetSystemMetrics(SM_CXFRAME)
        End Select

    End If

    'convert to whatever scale the form is using'
    GetFrameWidth = frm.ScaleX(nFinalWidth, vbPixels, frm.ScaleMode)

End Function

Private Function GetBorderWidth(ByVal frm As Form) As Long

    Dim nFinalWidth As Long

    If frm.ControlBox Then

        Select Case frm.Appearance

            Case 0 'flat'
                nFinalWidth = GetSystemMetrics(SM_CXBORDER)
            Case 1 '3D'
                nFinalWidth = GetSystemMetrics(SM_CXEDGE)
        End Select

    End If

    'convert to whatever scale the form is using'
    GetBorderWidth = frm.ScaleX(nFinalWidth, vbPixels, frm.ScaleMode)

End Function

Public Function GetRecommendedWidth(ByVal frm As Form) As Long

    Dim nNewWidth As Long

    ' An abitrary amount of extra padding so that the caption text '
    ' is not scrunched up against the min/max/close buttons '

    Const PADDING_TWIPS = 120

    nNewWidth = _
        GetCaptionTextWidth(frm) _
        + GetControlBoxWidth(frm) _
        + GetIconWidth(frm) _
        + GetFrameWidth(frm) * 2 _
        + GetBorderWidth(frm) * 2 _
        + PADDING_TWIPS

    If nNewWidth > frm.Width Then
        GetRecommendedWidth = nNewWidth
    Else
        GetRecommendedWidth = frm.Width
    End If

End Function

Затем поместите следующее в событие Form_Load

Private Sub Form_Load()

    Me.Caption = String(100, "x") 'replace this with your caption'
    Me.Width = GetRecommendedWidth(Me)

End Sub
1 голос
/ 27 сентября 2008

Похоже, что VB6 ограничивает свойство App.Title до 40 символов. К сожалению, я не могу найти документацию по MSDN, подробно описывающую это поведение. (И, к сожалению, у меня нет документации, загруженной на компьютер, где все еще находится моя копия VB6.)

Я провел эксперимент с длинными заголовками, и это было наблюдаемое поведение. Если ваш заголовок длиннее 40 символов, он просто обрезается.

0 голосов
/ 27 сентября 2008

+ 1 давидг.

Вы уверены, что имеете в виду Название? Название - это то, что появляется на панели задач Windows. Используйте заголовок, чтобы установить текст в строке заголовка формы.

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