2016-03-30 14 views
1

Wenn Sie auf die "Dropdown" -Schaltfläche einer Combobox klicken, erscheint die Dropdownliste unter die Combobox, sofern nicht genug Platz unter, in diesem Fall die Listbox erscheint über.Forcieren einer Combobox zu "DropDown" oben statt unten

Jetzt frage ich mich, ob es eine Möglichkeit gibt, die lisbox über die Combobox zu erzwingen, auch wenn es genug Platz unter.

Illustration

Wenn ich auf der Box Combo klicken, würde Ich mag das „drop down“ Listenfeld erscheint oben auf der linken Bildschirmkopie immer.

enter image description here

+0

Nicht möglich von dem, was ich weiß ... dies wird von der Steuerung, die die Liste malt behandelt. Jetzt können Sie dieses Steuerelement immer ableiten und die Paint-Methode überschreiben ... –

+0

So behandelt Windows das Kombinationsfeld und die Menüs, das können Sie nicht ändern. Überschreiben der Farbe oder des Zeichens wird es nicht ändern. Möglicherweise müssen Sie Ihr eigenes benutzerdefiniertes Steuerelement von Grund auf neu schreiben. Lass die Idee fallen! – Ajay

Antwort

3

Alles ist möglich, und Sie brauchen nicht die Kontrolle „von Grund auf“ zu implementieren.

Zuerst können Sie den ListBox-Teil Ihrer ComboBox ableiten, um die vollständige Kontrolle darüber zu erhalten, wie in MSDN erläutert. Sie können eine von CListBox abgeleitete Klasse mithilfe des Klassenassistenten erstellen. Sie müssen nur WM_WINPOSITIONCHANGING Handler darin implementieren:

void CTopListBox::OnWindowPosChanging(WINDOWPOS* lpwndpos) 
{ 
    CListBox::OnWindowPosChanging(lpwndpos); 
    if ((lpwndpos->flags & SWP_NOMOVE) == 0) 
    { 
     lpwndpos->y -= lpwndpos->cy + 30; 
    } 
} 

hier der Einfachheit halber werde ich die Box nach oben durch die (Höhen + 30) zu bewegen. Sie können die Höhe Ihrer ComboBox anstelle meiner 30 erhalten.

Dann deklarieren Sie eine Membervariable in der Dialogklasse:

CTopListBox m_listbox; 

und Unterklasse es wie folgt aus:

HBRUSH CMFCDlgDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{ 
    if (nCtlColor == CTLCOLOR_LISTBOX) 
    { 
     if (m_listbox.GetSafeHwnd() == NULL) 
     { 
      m_listbox.SubclassWindow(pWnd->GetSafeHwnd()); 
      CRect r; 
      m_listbox.GetWindowRect(r); 
      m_listbox.MoveWindow(r); 
     } 
    } 

    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor); 
    return hbr; 
} 

Bitte beachte, dass ich m_listbox.MoveWindow(r) es nenne; es wird benötigt, weil zuerst die Nachricht WM_CONTROLCOLOR für dieses Listenfeld kommt, nachdem es positioniert ist, also das allererste Mal, dass es anstatt nach oben fallen würde.

Haftungsausschluss: Dies ist keine sehr saubere Lösung, da, wenn Sie Windows-Animation aktiviert haben, Sie sehen, dass die Liste von oben nach unten entrollt.

Alternativ können Sie die Combobox "täuschen", dass es zu nahe am unteren Bildschirmrand ist; dann wird es von selbst fallen. Ich lasse es als eine Übung für die Leser :)

+3

Subclassing ist viel einfacher bei der Verwendung von GetComboBoxInfo. Es ist auch möglich, dies in CBN_DROPDOWN zu behandeln. – xMRi

1

Dies wäre relativ einfach, außer wenn Combo-Box "Folie offen" -Effekt hat. Wenn Sie die Dropdown-Listbox nach oben verschieben und die Combo-Folien von oben nach unten öffnen, würde das seltsam aussehen. Sie müssen also die Animation deaktivieren oder umkehren.

In dieser Funktion rufe ich AnimateWindow in OnWindowPosChanging, es scheint keine Probleme zu verursachen, aber ich bin nicht 100% sicher darüber!

class CComboBox_ListBox : public CListBox 
{ 
public: 
    CWnd *comboBox; 
    void OnWindowPosChanging(WINDOWPOS *wndpos) 
    { 
     CListBox::OnWindowPosChanging(wndpos); 
     if (comboBox && wndpos->cx && wndpos->cy && !(wndpos->flags & SWP_NOMOVE)) 
     { 
      CRect rc; 
      comboBox->GetWindowRect(&rc); 

      //if listbox is at the bottom... 
      if (wndpos->y > rc.top) { 
       //if there is enough room for listbox to go on top... 
       if (rc.top > wndpos->cy) { 
        wndpos->y = rc.top - wndpos->cy; 
        BOOL animation; 
        SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &animation, 0); 
        //if combobox slides open... 
        if (animation) { 
         //we have to set the x coordinate otherwise listbox 
         //is in the wrong place when parent window moves 
         SetWindowPos(0, wndpos->x, wndpos->y, 0, 0, 
          SWP_NOSENDCHANGING | SWP_HIDEWINDOW | SWP_NOSIZE); 

         AnimateWindow(100, AW_VER_NEGATIVE); 
        } 
       } 
      } 
     } 
    } 
    DECLARE_MESSAGE_MAP() 
}; 

Verbrauch:

COMBOBOXINFO ci = { sizeof(COMBOBOXINFO) }; 
comboBox.GetComboBoxInfo(&ci); 
CComboBox_ListBox *listBox = new CComboBox_ListBox; 
listBox->comboBox = &comboBox; 
listBox->SubclassWindow(ci.hwndList); 

Sie können auch SetMinVisibleItems verwenden, um die listbox Höhe zu reduzieren und sicherzustellen, dass die Drop-Down-Liste auf passt.

+0

'OnWindowPosChanging' wird aus vielen Gründen aufgerufen (aktivieren, usw.); Sie müssen das 'SWP_NOMOVE'-Flag überprüfen, um zu sehen, ob sich die Größe ändert. –

+0

@Vlad Ich teste 'cx' und' cy', ich denke, das ist das Gleiche. Ich habe 'SWP_NOMOVE' Test hinzugefügt, um sicher zu sein –

+0

Nur eine Position zu testen ist NICHT genug - wenn das Flag' SWP_NOMOVE' gesetzt ist, können sie 0 sein. –