Dimensionando a caixa suspensa ComboBox

o TComboBox O componente combina uma caixa de edição com uma lista de "seleção" rolável. Os usuários podem selecionar um item da lista ou digitar diretamente no caixa de edição.

Lista suspensa

Quando uma caixa de combinação está no estado suspenso, o Windows desenha um tipo de controle de caixa de listagem para exibir os itens da caixa de combinação para seleção.

o Propriedade DropDownCount especifica o número máximo de itens exibidos na lista suspensa.

o largura da lista suspensa Por padrão, seria igual à largura da caixa de combinação.

Quando o comprimento (de uma sequência) de itens excede a largura da caixa de combinação, os itens são exibidos como recorte!

O TComboBox não fornece uma maneira de definir a largura da sua lista suspensa :(

Corrigindo a largura da lista suspensa ComboBox

Podemos definir a largura da lista suspensa enviando uma mensagem especial. Mensagem do Windows para a caixa de combinação. A mensagem é CB_SETDROPPEDWIDTH e envia a largura mínima permitida, em pixels, da caixa de listagem de uma caixa de combinação.

instagram viewer

Para codificar o tamanho da lista suspensa para, digamos, 200 pixels, você pode:


SendMessage (theComboBox. Alça, CB_SETDROPPEDWIDTH, 200, 0); 

Isso só está ok se você tiver certeza de que toda a sua theComboBox. Os itens não têm mais de 200 px (quando desenhados).

Para garantir que sempre tenhamos a lista suspensa exibida suficientemente larga, podemos calcular a largura necessária.

Aqui está uma função para obter a largura necessária da lista suspensa e configurá-la:

procedimento ComboBox_AutoWidth (const theComboBox: TCombobox); const
HORIZONTAL_PADDING = 4; var
itemsFullWidth: inteiro; idx: inteiro; itemWidth: inteiro; início
itemsFullWidth: = 0; // obtém o máximo necessário com os itens no estado suspensopara idx: = 0 para -1 + theComboBox. Itens. Contagem Fazinício
itemWidth: = theComboBox. Tela de pintura. TextWidth (theComboBox. Itens [idx]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) então itemsFullWidth: = itemWidth; fim; // defina a largura da lista suspensa, se necessárioE se (itemsFullWidth> theComboBox. Largura) então. início// verifica se haverá uma barra de rolagemE se theComboBox. DropDownCount então
itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox. Identificador, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); fim; fim; 

A largura da cadeia mais longa é usada para a largura da lista suspensa.

Quando chamar ComboBox_AutoWidth?
Se você pré-preencher a lista de itens (em tempo de design ou ao criar o formulário), poderá chamar o procedimento ComboBox_AutoWidth dentro do formulário OnCreate manipulador de eventos.

Se você alterar dinamicamente a lista de itens da caixa de combinação, poderá chamar o procedimento ComboBox_AutoWidth dentro do OnDropDown manipulador de eventos - ocorre quando o usuário abre a lista suspensa.

Um teste
Para um teste, temos 3 caixas de combinação em um formulário. Todos têm itens com o texto mais amplo que a largura real da caixa de combinação. A terceira caixa de combinação é colocada perto da borda direita da borda do formulário.

A propriedade Items, neste exemplo, é pré-preenchida - chamamos nosso ComboBox_AutoWidth no manipulador de eventos OnCreate para o formulário:

// OnCreate do formulárioprocedimento TForm. FormCreate (Remetente: TObject); início
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); fim; 

Não chamamos ComboBox_AutoWidth para Combobox1 para ver a diferença!

Observe que, quando executado, a lista suspensa do Combobox2 será mais ampla que o Combobox2.

A lista suspensa inteira é cortada para "posicionamento próximo à borda direita"

Para o Combobox3, aquele colocado próximo à borda direita, a lista suspensa é cortada.

Enviar o CB_SETDROPPEDWIDTH sempre estenderá a caixa de listagem suspensa para a direita. Quando sua caixa de combinação estiver próxima à borda direita, estender a caixa de listagem mais para a direita resultaria no corte da exibição da caixa de listagem.

De alguma forma, precisamos estender a caixa de listagem para a esquerda quando for esse o caso, não para a direita!

O CB_SETDROPPEDWIDTH não tem como especificar em qual direção (esquerda ou direita) estender a caixa de listagem.

Solução: WM_CTLCOLORLISTBOX

Apenas quando a lista suspensa deve ser exibida, o Windows envia a mensagem WM_CTLCOLORLISTBOX para a janela pai de uma caixa de listagem - para nossa caixa de combinação.

Ser capaz de lidar com o WM_CTLCOLORLISTBOX para a caixa de combinação da borda quase direita resolveria o problema.

O Todo-Poderoso WindowProc
Cada controle VCL expõe a propriedade WindowProc - o procedimento que responde às mensagens enviadas ao controle. Podemos usar a propriedade WindowProc para substituir ou subclassificar temporariamente o procedimento de janela do controle.

Aqui está o nosso WindowProc modificado para Combobox3 (aquele próximo à borda direita):

// ComboBox3 WindowProc modificadoprocedimento TForm. ComboBox3WindowProc (var Mensagem: TMessage); var
cr, lbr: TRect; início// desenhando a caixa de listagem com itens da caixa de combinação
se Mensagem. Msg = WM_CTLCOLORLISTBOX então. início
GetWindowRect (ComboBox3.Handle, cr); // retângulo da caixa de listagem
GetWindowRect (mensagem. LParam, lbr); // mova para a esquerda para corresponder à borda direitaE se cr. Direita <> lbr. Certo então
MoveWindow (Mensagem. LParam, lbr. Esquerda- (lbr. Clbr direito. Certo), lbr. Top, lbr. Direito-lbr. Esquerda, lbr. Bottom-lbr. Top, True); fimoutro
ComboBox3WindowProcORIGINAL (mensagem); fim; 

Se a mensagem que nossa caixa de combinação recebe for WM_CTLCOLORLISTBOX, obtemos o retângulo da janela, também obtemos o retângulo da caixa de listagem a ser exibida (GetWindowRect). Se parecer que a caixa de listagem apareceria mais à direita - nós a moveremos para a esquerda, para que a borda direita da caixa de combinação e da caixa de listagem seja a mesma. Tão fácil quanto isso :)

Se a mensagem não for WM_CTLCOLORLISTBOX, simplesmente chamamos o procedimento original de manipulação de mensagens para a caixa de combinação (ComboBox3WindowProcORIGINAL).

Por fim, tudo isso pode funcionar se tivermos definido corretamente (no manipulador de eventos OnCreate para o formulário):

// OnCreate do formulárioprocedimento TForm. FormCreate (Remetente: TObject); início
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // anexa WindowProc modificado / personalizado para ComboBox3
ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; fim; 

Onde na declaração do formulário temos (inteiro):

tipo
TForm = classe(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox;procedimento FormCreate (Remetente: TObject); privado
ComboBox3WindowProcORIGINAL: TWndMethod; procedimento ComboBox3WindowProc (var Mensagem: TMessage); público{Declarações públicas}fim; 

E é isso. Tudo tratado :)

instagram story viewer