QML does not come (yet?) with the equivalent of a QComboBox. As I find a ComboBox quite useful, even for touch UIs, I wrote a simple wrapper / adapter or whatever you want to call it that enables using a QComboBox in QML. Thereby the goal was to integrate the native QComboBox Qt widget as good as possible with QML, i.e., give it the look and feel of QML and make it work with the touch UI. The following pictures show the “QML’ed” QComboBox in action in MeePasswords on Maemo Fremantle and MeeGo / Harmattan respectively.
The C++ code consists of three parts.
The header file (qcomboboxqmladapter.h):
#ifndef QCOMBOBOXQMLADAPTER_H #define QCOMBOBOXQMLADAPTER_H #include #include #include #include #include "entrylistmodel.h" class CustomComboBox : public QComboBox { Q_OBJECT public: explicit CustomComboBox(QWidget *parent = 0) : QComboBox(parent){} protected: void focusInEvent(QFocusEvent *event){ QComboBox::focusInEvent(event); emit focusIn(); } void focusOutEvent(QFocusEvent *event){ QComboBox::focusOutEvent(event); emit focusOut(); } signals: void focusIn(); void focusOut(); }; class QComboBoxQmlAdapter : public QGraphicsProxyWidget { Q_OBJECT Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) public: explicit QComboBoxQmlAdapter(QGraphicsItem *parent = 0); ~QComboBoxQmlAdapter(); void setText(const QString text) { m_comboBox->setEditText(text); } QString text() { return m_comboBox->currentText(); } Q_INVOKABLE void setItems(const QStringList &items); signals: void focusIn(); void focusOut(); void textChanged(QString text); private: CustomComboBox *m_comboBox; }; #endif // QCOMBOBOXQMLADAPTER_H
The *.cpp file (qcomboboxqmladapter.cpp):
#include "qcomboboxqmladapter.h" QComboBoxQmlAdapter::QComboBoxQmlAdapter(QGraphicsItem *parent) : QGraphicsProxyWidget(parent) { m_comboBox = new CustomComboBox(0); m_comboBox->setEditable(true); QFont font = QFont(m_comboBox->font().family(), 17); m_comboBox->setFont(font); m_comboBox->setFrame(false); #ifdef MEEGO_EDITION_HARMATTAN m_comboBox->setStyleSheet("QComboBox { border: 3px solid gray; border-radius: 18px; padding: 8px 20px 6px 8px; margin-top: 2px; border-color: lightgray; border-bottom-color: white; background: white; selection-background-color: rgb(70, 140, 250) }" "QComboBox:focus { border-color: rgb(70, 140, 250) }" "QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 40px; border-style: none; padding-right 10px; selection-background-color: rgb(70, 140, 250) }" "QComboBox::down-arrow { image: url(/usr/share/themes/blanco/meegotouch/icons/icon-m-toolbar-down.png); }" "QListView { selection-background-color: rgb(70, 140, 250); }" ); #elif defined(Q_WS_MAEMO_5) m_comboBox->setStyleSheet("QComboBox { border: 3px solid gray; border-radius: 18px; padding: 2px 20px 2px 8px; border-color: lightgray; background: white; selection-background-color: rgb(70, 140, 250) }" "QComboBox:focus { border-color: rgb(70, 140, 250) }" "QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 40px; border-style: none; padding-right 10px; selection-background-color: rgb(70, 140, 250) }" "QComboBox::down-arrow { image: url(/usr/share/themes/default/images/ComboBoxButtonNormal.png); }" "QListView { selection-background-color: rgb(70, 140, 250); }" ); #else m_comboBox->setStyleSheet("QComboBox { border: 3px solid gray; border-radius: 18px; padding: 8px 20px 8px 8px; border-color: lightgray; background: white; selection-background-color: rgb(70, 140, 250) }" "QComboBox:focus { border-color: rgb(70, 140, 250) }" "QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 40px; border-style: none; padding-right 10px; selection-background-color: rgb(70, 140, 250) }" "QListView { selection-background-color: rgb(70, 140, 250); }" ); #endif connect(m_comboBox, SIGNAL(focusIn()), this, SIGNAL(focusIn())); connect(m_comboBox, SIGNAL(focusOut()), this, SIGNAL(focusOut())); connect(m_comboBox, SIGNAL(currentIndexChanged(QString)), this, SIGNAL(textChanged(QString))); setWidget(m_comboBox); } QComboBoxQmlAdapter::~QComboBoxQmlAdapter(){ delete m_comboBox; } void QComboBoxQmlAdapter::setItems(const QStringList &items){ QString temp = m_comboBox->currentText(); m_comboBox->clear(); m_comboBox->addItems(items); m_comboBox->setEditText(temp); }
Then our new “QML ComboBox” needs to be registered such that it can be used in QML. This can be done, e.g., in the main.cpp file, as follows:
#include #include "qcomboboxqmladapter.h" Q_DECL_EXPORT int main(int argc, char *argv[]) { ... /* * The following code registers the class QComboBoxQmlAdapter as QML * element "QComboBox" in the QML plugin "meepasswords" with version 1.0. */ qmlRegisterType("meepasswords", 1, 0, "QComboBox"); ... }
Finally, we can use our new QML QComboBox as follows (this code is taken from the MeeGo / Harmattan version of MeePasswords):
... import meepasswords 1.0 ... QComboBox{id: categoryInput; width: 0.5 * parent.width; z: 3 TextInput{ id: textInput } onFocusIn: textInput.openSoftwareInputPanel() onFocusOut: textInput.closeSoftwareInputPanel() Component.onCompleted: { categoryInput.setItems(["foo", "bar", "snafu"]) } } ...
In this example the combobox is “filled” with items via a hardcoded list of strings in Component.onCompleted. In a real application one would most probably use something which is more dynamic. Though as an example this should suffice.
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Hi, congratulations for you code, this project helped me with mine.
However you let me make a correction, in the main file to register the class instruction should be
qmlRegisterType < QComboBoxQmlAdapter,1 > (“meepasswords”, 1, 0, “QComboBox”);
We must also add the library qmldeclarative.h by a bug in QT4.7
“” Since qmlRegisterType is listed as related to QDeclarativeEngine it would seem logical to #include in order to be able to use the qmlRegisterType function. However, this is not the case. Instead, you must #include . This is not mentioned in the documentation. I actually had to grep the source code to figure this out! “”
https://bugreports.qt-project.org/browse/QTBUG-15630
QComboBoxQmlAdapter::~QComboBoxQmlAdapter(){
delete m_comboBox; // — is not necessary, because m_comboBox destroyed as child of QGraphicsProxyWidget (result of setWidget)
}