Dynamic translation of combobox qml
up vote
0
down vote
favorite
I've added translation to my qt/qml app using this tutorial
https://retifrav.github.io/blog/2017/01/04/translating-qml-app/
https://github.com/retifrav/translating-qml
And most seems to work well except that the values of the combobox dont get update with dynamic translate.
Im using qt 5.11.2.
By a combobox i mean this:
ComboBox {
textRole: "text"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({text: qsTr("None")})
append({text: qsTr("Subpanel")})
append({text: qsTr("All")})
}
}
}
ComboBox {
textRole: "text"
Layout.fillWidth: true
model: ListModel {
ListElement{text: qsTr("None")}
ListElement{text: qsTr("Subpanel")}
ListElement{text: qsTr("All")}
}
}
None of them gets updated.
I've done some research and found this on bug reports
https://bugreports.qt.io/browse/QTBUG-68350
This seems to get fixed on 5.12, but for various reason we need to keep the same version, is there a way i can fix it for this version? (5.11.2)
EDIT: I dont find a way to translate comboBox. Is there another way of doing translations? even if it means to open a new instance of the app? Can someone point me to a link? Can't find a way to do this.
EDIT2: Is there a way to force the model of the combobox to be updated by javascript? when the changeLanguage() method is called?
note: As a complaint i'm finding the support / community to get answers for Qt problems terrible, really bad, but maybe its my problem.
qt qml
This question has an open bounty worth +50
reputation from Nmaster88 ending in 3 days.
This question has not received enough attention.
add a comment |
up vote
0
down vote
favorite
I've added translation to my qt/qml app using this tutorial
https://retifrav.github.io/blog/2017/01/04/translating-qml-app/
https://github.com/retifrav/translating-qml
And most seems to work well except that the values of the combobox dont get update with dynamic translate.
Im using qt 5.11.2.
By a combobox i mean this:
ComboBox {
textRole: "text"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({text: qsTr("None")})
append({text: qsTr("Subpanel")})
append({text: qsTr("All")})
}
}
}
ComboBox {
textRole: "text"
Layout.fillWidth: true
model: ListModel {
ListElement{text: qsTr("None")}
ListElement{text: qsTr("Subpanel")}
ListElement{text: qsTr("All")}
}
}
None of them gets updated.
I've done some research and found this on bug reports
https://bugreports.qt.io/browse/QTBUG-68350
This seems to get fixed on 5.12, but for various reason we need to keep the same version, is there a way i can fix it for this version? (5.11.2)
EDIT: I dont find a way to translate comboBox. Is there another way of doing translations? even if it means to open a new instance of the app? Can someone point me to a link? Can't find a way to do this.
EDIT2: Is there a way to force the model of the combobox to be updated by javascript? when the changeLanguage() method is called?
note: As a complaint i'm finding the support / community to get answers for Qt problems terrible, really bad, but maybe its my problem.
qt qml
This question has an open bounty worth +50
reputation from Nmaster88 ending in 3 days.
This question has not received enough attention.
Create hiddenLabel
s and define the texts there. Then let the list elements bind to those labels. That could work
– Felix
Nov 13 at 9:50
Or create a QAbstractListModel with your texts, this way you can even tie a certain value to a certain text
– Amfasis
Nov 13 at 10:10
@Felix that doesnt work.
– Nmaster88
Nov 13 at 15:45
@Amfasis can you give an example on how i can do that? thanks
– Nmaster88
Nov 13 at 15:45
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I've added translation to my qt/qml app using this tutorial
https://retifrav.github.io/blog/2017/01/04/translating-qml-app/
https://github.com/retifrav/translating-qml
And most seems to work well except that the values of the combobox dont get update with dynamic translate.
Im using qt 5.11.2.
By a combobox i mean this:
ComboBox {
textRole: "text"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({text: qsTr("None")})
append({text: qsTr("Subpanel")})
append({text: qsTr("All")})
}
}
}
ComboBox {
textRole: "text"
Layout.fillWidth: true
model: ListModel {
ListElement{text: qsTr("None")}
ListElement{text: qsTr("Subpanel")}
ListElement{text: qsTr("All")}
}
}
None of them gets updated.
I've done some research and found this on bug reports
https://bugreports.qt.io/browse/QTBUG-68350
This seems to get fixed on 5.12, but for various reason we need to keep the same version, is there a way i can fix it for this version? (5.11.2)
EDIT: I dont find a way to translate comboBox. Is there another way of doing translations? even if it means to open a new instance of the app? Can someone point me to a link? Can't find a way to do this.
EDIT2: Is there a way to force the model of the combobox to be updated by javascript? when the changeLanguage() method is called?
note: As a complaint i'm finding the support / community to get answers for Qt problems terrible, really bad, but maybe its my problem.
qt qml
I've added translation to my qt/qml app using this tutorial
https://retifrav.github.io/blog/2017/01/04/translating-qml-app/
https://github.com/retifrav/translating-qml
And most seems to work well except that the values of the combobox dont get update with dynamic translate.
Im using qt 5.11.2.
By a combobox i mean this:
ComboBox {
textRole: "text"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({text: qsTr("None")})
append({text: qsTr("Subpanel")})
append({text: qsTr("All")})
}
}
}
ComboBox {
textRole: "text"
Layout.fillWidth: true
model: ListModel {
ListElement{text: qsTr("None")}
ListElement{text: qsTr("Subpanel")}
ListElement{text: qsTr("All")}
}
}
None of them gets updated.
I've done some research and found this on bug reports
https://bugreports.qt.io/browse/QTBUG-68350
This seems to get fixed on 5.12, but for various reason we need to keep the same version, is there a way i can fix it for this version? (5.11.2)
EDIT: I dont find a way to translate comboBox. Is there another way of doing translations? even if it means to open a new instance of the app? Can someone point me to a link? Can't find a way to do this.
EDIT2: Is there a way to force the model of the combobox to be updated by javascript? when the changeLanguage() method is called?
note: As a complaint i'm finding the support / community to get answers for Qt problems terrible, really bad, but maybe its my problem.
qt qml
qt qml
edited Nov 16 at 12:14
asked Nov 13 at 9:24
Nmaster88
281117
281117
This question has an open bounty worth +50
reputation from Nmaster88 ending in 3 days.
This question has not received enough attention.
This question has an open bounty worth +50
reputation from Nmaster88 ending in 3 days.
This question has not received enough attention.
Create hiddenLabel
s and define the texts there. Then let the list elements bind to those labels. That could work
– Felix
Nov 13 at 9:50
Or create a QAbstractListModel with your texts, this way you can even tie a certain value to a certain text
– Amfasis
Nov 13 at 10:10
@Felix that doesnt work.
– Nmaster88
Nov 13 at 15:45
@Amfasis can you give an example on how i can do that? thanks
– Nmaster88
Nov 13 at 15:45
add a comment |
Create hiddenLabel
s and define the texts there. Then let the list elements bind to those labels. That could work
– Felix
Nov 13 at 9:50
Or create a QAbstractListModel with your texts, this way you can even tie a certain value to a certain text
– Amfasis
Nov 13 at 10:10
@Felix that doesnt work.
– Nmaster88
Nov 13 at 15:45
@Amfasis can you give an example on how i can do that? thanks
– Nmaster88
Nov 13 at 15:45
Create hidden
Label
s and define the texts there. Then let the list elements bind to those labels. That could work– Felix
Nov 13 at 9:50
Create hidden
Label
s and define the texts there. Then let the list elements bind to those labels. That could work– Felix
Nov 13 at 9:50
Or create a QAbstractListModel with your texts, this way you can even tie a certain value to a certain text
– Amfasis
Nov 13 at 10:10
Or create a QAbstractListModel with your texts, this way you can even tie a certain value to a certain text
– Amfasis
Nov 13 at 10:10
@Felix that doesnt work.
– Nmaster88
Nov 13 at 15:45
@Felix that doesnt work.
– Nmaster88
Nov 13 at 15:45
@Amfasis can you give an example on how i can do that? thanks
– Nmaster88
Nov 13 at 15:45
@Amfasis can you give an example on how i can do that? thanks
– Nmaster88
Nov 13 at 15:45
add a comment |
3 Answers
3
active
oldest
votes
up vote
1
down vote
One option is to add a QAbstracstListModel
which does the translation. I made myself a base class, which can be inherited. This also gives you a lot of flexibility for converting a selected item to a value (in this example I am using int, but you can make it anything), which is connected to a C++ backend (I used backend.selectedPanel
for your example)
<< Edit: See answer of Felix for nice addition of dynamic translation >>
base header:
class baseEnum : public QAbstractListModel
{
Q_OBJECT
public:
virtual int rowCount(const QModelIndex &parent) const = 0;
virtual QVariant data(const QModelIndex &index, int role) const = 0;
QHash<int, QByteArray> roleNames() const;
Q_INVOKABLE int getIndex(int value);
Q_INVOKABLE int getValue(int index);
}
base cpp:
QHash<int, QByteArray> baseEnum::roleNames() const
{
QHash<int, QByteArray> result;
result.insert(Qt::DisplayRole, "text");
result.insert(Qt::UserRole + 1, "value");
return result;
}
int baseEnum::getIndex(int value)
{
for(int i=0;i<rowCount(QModelIndex());++i)
if(data(createIndex(i, 0, nullptr), Qt::UserRole + 1).toInt() == value)
return i;
return -1;
}
int baseEnum::getValue(int index)
{
return data(createIndex(index, 0, nullptr), Qt::UserRole + 1).toInt();
}
derived header:
class FancyEnum : public baseEnum
{
Q_OBJECT
public:
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
};
derived cpp:
int FancyEnum::rowCount(const QModelIndex &parent) const
{
if(!parent.isValid())
return 5;
return 0;
}
QVariant FancyEnum::data(const QModelIndex &index, int role) const
{
switch(index.row())
{
case 0: return role == Qt::DisplayRole ? QVariant(tr("None")) : QVariant(0);
case 1: return role == Qt::DisplayRole ? QVariant(tr("Subpanel")) : QVariant(1);
case 2: return role == Qt::DisplayRole ? QVariant(tr("All")) : QVariant(2);
}
return role == Qt::DisplayRole ? QVariant(QString("<%1>").arg(index.row())) : QVariant(0);
}
Register it somewhere:
qmlRegisterType<FancyEnum>("your.path.here", 1, 0, "FancyEnum");
usage in QML:
ComboBox {
model: FancyEnum { id: myEnum }
textRole: "text"
currentIndex: myEnum.getIndex(backend.selectedPanel) : 0
onActivated: backend.selectedPanel = myEnum.getValue(index) }
}
thanks a lot for the answer. i tried this solution i added the 2 classes, registeres the type on the main.cpp (qmlRegisterType<FancyEnum>("pt.gfe.connector", 1, 0, "FancyEnum");) and the called the model in combobox like you do but doesn't work. Is this tested to work? (in QT version 5.11)
– Nmaster88
Nov 15 at 16:39
You will propably have to capture the retranslate event and "reset" the model so the gui gets notified of the change
– Felix
Nov 16 at 12:15
@Felix how do you suggest doing that?
– Nmaster88
Nov 16 at 12:23
@Nmaster88 This is already used in production code, albeit not with the dynamic translation. Is that what you describe as not working?
– Amfasis
Nov 16 at 13:23
@Amfasis yes, my problem is related with dynamic translation.
– Nmaster88
Nov 16 at 14:10
|
show 2 more comments
up vote
1
down vote
This is an addition to @Amfasis answer. It extends the very useful "baseEnum" model by adding the capability to detect and react to restranslation events
For the GUI to actually detect that the text was changed after a restranslation, the model must "notify" the gui that data has changed. However, to do that, the model must know when data changed. Thankfully, Qt has the LanguageChange event to do so. The following code catches that event and uses it to notify the gui of the data change.
// in the header file:
class baseEnum : public QAbstractListModel
{
Q_OBJECT
public:
// ... all the stuff from before
bool event(QEvent *event);
};
// and in the cpp file:
bool baseEnum::event(QEvent *ev)
{
if(ev) {
switch(ev->type()) {
case QEvent::LanguageChange:
// notifiy models that the display data has changed for all rows
emit dataChanged(index(0),
index(rowCount(QModelIndex{}) - 1),
{Qt::DisplayRole});
break;
}
}
return QAbstractListModel::event(ev);
}
thanks for this addition :-D I will actually also start using it in my projects :thumbsup:
– Amfasis
Nov 16 at 13:18
@Felix i've added those function to baseEnum class, but rowCount() is not defined there, it's on fancyEnum, how do i call that function? thanks
– Nmaster88
Nov 16 at 14:50
It is declared as pure virtual function and implemented in the FancyEnum model. You can still call it from the base class just like any other normal method
– Felix
Nov 16 at 17:51
@Nmaster88 I also got an error, needed to putrowCount(QModelIndx())
instead. Alsoevent(QEvent*)
is expected to have a bool return value in my version of Qt, not sure if it was changed
– Amfasis
yesterday
Ah yes, I simply screwed up the bool part. Also, InQAbstractListModel
, rowCount is declared asint rowCount(const QModelIndex &parent = QModelIndex()) const
- which is why you can call it without a parameter normally - but as I can see now, in @Amfasis answer he did not specify the default argument again. I will update my answer accordingly
– Felix
yesterday
add a comment |
up vote
0
down vote
Unfortunately, I can't test all the cases at the moment (and I don't have an access to the Qt 5.11.2), but I think this should work:
ComboBox {
textRole: "text"
Layout.fillWidth: true
displayText: qsTr(currentText)
model: ListModel {
ListElement{text: "None"}
ListElement{text: "Subpanel"}
ListElement{text: "All"}
}
delegate: Button {
width: ListView.view.width
text: qsTr(model.text)
}
}
Or, another way is to re-create a model when language is changed:
ComboBox {
id: combobox
textRole: "text"
Layout.fillWidth: true
model: ListModel {
dynamicRoles: true
}
Component.onCompleted: {
reload()
}
Connections {
target: trans // this is a translator from a git project you are referring to
onLanguageChanged: {
combobox.reload()
}
}
function reload() {
var i = combobox.currentIndex
combobox.model = [
{text: qsTr("None")},
{text: qsTr("Subpanel")},
{text: qsTr("All")}
]
combobox.currentIndex = i
}
}
In the first example you need to useQT_TR_NOOP
in theListModel
so thatlupdate
knows there is a string to be translated
– Amfasis
2 days ago
@Amfasis, could you please clarify why do I need to use it?
– Andrii
yesterday
The tool that searches for text that should be translated (lupdate
) does not look through if there is a variable in theqsTr(...)
call, so it will not translate the three items in yourListModel
(ok, there is a chance it will find the same text already translated and use that, but that's not good programming IMHO)
– Amfasis
yesterday
got it, thank you
– Andrii
yesterday
add a comment |
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
One option is to add a QAbstracstListModel
which does the translation. I made myself a base class, which can be inherited. This also gives you a lot of flexibility for converting a selected item to a value (in this example I am using int, but you can make it anything), which is connected to a C++ backend (I used backend.selectedPanel
for your example)
<< Edit: See answer of Felix for nice addition of dynamic translation >>
base header:
class baseEnum : public QAbstractListModel
{
Q_OBJECT
public:
virtual int rowCount(const QModelIndex &parent) const = 0;
virtual QVariant data(const QModelIndex &index, int role) const = 0;
QHash<int, QByteArray> roleNames() const;
Q_INVOKABLE int getIndex(int value);
Q_INVOKABLE int getValue(int index);
}
base cpp:
QHash<int, QByteArray> baseEnum::roleNames() const
{
QHash<int, QByteArray> result;
result.insert(Qt::DisplayRole, "text");
result.insert(Qt::UserRole + 1, "value");
return result;
}
int baseEnum::getIndex(int value)
{
for(int i=0;i<rowCount(QModelIndex());++i)
if(data(createIndex(i, 0, nullptr), Qt::UserRole + 1).toInt() == value)
return i;
return -1;
}
int baseEnum::getValue(int index)
{
return data(createIndex(index, 0, nullptr), Qt::UserRole + 1).toInt();
}
derived header:
class FancyEnum : public baseEnum
{
Q_OBJECT
public:
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
};
derived cpp:
int FancyEnum::rowCount(const QModelIndex &parent) const
{
if(!parent.isValid())
return 5;
return 0;
}
QVariant FancyEnum::data(const QModelIndex &index, int role) const
{
switch(index.row())
{
case 0: return role == Qt::DisplayRole ? QVariant(tr("None")) : QVariant(0);
case 1: return role == Qt::DisplayRole ? QVariant(tr("Subpanel")) : QVariant(1);
case 2: return role == Qt::DisplayRole ? QVariant(tr("All")) : QVariant(2);
}
return role == Qt::DisplayRole ? QVariant(QString("<%1>").arg(index.row())) : QVariant(0);
}
Register it somewhere:
qmlRegisterType<FancyEnum>("your.path.here", 1, 0, "FancyEnum");
usage in QML:
ComboBox {
model: FancyEnum { id: myEnum }
textRole: "text"
currentIndex: myEnum.getIndex(backend.selectedPanel) : 0
onActivated: backend.selectedPanel = myEnum.getValue(index) }
}
thanks a lot for the answer. i tried this solution i added the 2 classes, registeres the type on the main.cpp (qmlRegisterType<FancyEnum>("pt.gfe.connector", 1, 0, "FancyEnum");) and the called the model in combobox like you do but doesn't work. Is this tested to work? (in QT version 5.11)
– Nmaster88
Nov 15 at 16:39
You will propably have to capture the retranslate event and "reset" the model so the gui gets notified of the change
– Felix
Nov 16 at 12:15
@Felix how do you suggest doing that?
– Nmaster88
Nov 16 at 12:23
@Nmaster88 This is already used in production code, albeit not with the dynamic translation. Is that what you describe as not working?
– Amfasis
Nov 16 at 13:23
@Amfasis yes, my problem is related with dynamic translation.
– Nmaster88
Nov 16 at 14:10
|
show 2 more comments
up vote
1
down vote
One option is to add a QAbstracstListModel
which does the translation. I made myself a base class, which can be inherited. This also gives you a lot of flexibility for converting a selected item to a value (in this example I am using int, but you can make it anything), which is connected to a C++ backend (I used backend.selectedPanel
for your example)
<< Edit: See answer of Felix for nice addition of dynamic translation >>
base header:
class baseEnum : public QAbstractListModel
{
Q_OBJECT
public:
virtual int rowCount(const QModelIndex &parent) const = 0;
virtual QVariant data(const QModelIndex &index, int role) const = 0;
QHash<int, QByteArray> roleNames() const;
Q_INVOKABLE int getIndex(int value);
Q_INVOKABLE int getValue(int index);
}
base cpp:
QHash<int, QByteArray> baseEnum::roleNames() const
{
QHash<int, QByteArray> result;
result.insert(Qt::DisplayRole, "text");
result.insert(Qt::UserRole + 1, "value");
return result;
}
int baseEnum::getIndex(int value)
{
for(int i=0;i<rowCount(QModelIndex());++i)
if(data(createIndex(i, 0, nullptr), Qt::UserRole + 1).toInt() == value)
return i;
return -1;
}
int baseEnum::getValue(int index)
{
return data(createIndex(index, 0, nullptr), Qt::UserRole + 1).toInt();
}
derived header:
class FancyEnum : public baseEnum
{
Q_OBJECT
public:
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
};
derived cpp:
int FancyEnum::rowCount(const QModelIndex &parent) const
{
if(!parent.isValid())
return 5;
return 0;
}
QVariant FancyEnum::data(const QModelIndex &index, int role) const
{
switch(index.row())
{
case 0: return role == Qt::DisplayRole ? QVariant(tr("None")) : QVariant(0);
case 1: return role == Qt::DisplayRole ? QVariant(tr("Subpanel")) : QVariant(1);
case 2: return role == Qt::DisplayRole ? QVariant(tr("All")) : QVariant(2);
}
return role == Qt::DisplayRole ? QVariant(QString("<%1>").arg(index.row())) : QVariant(0);
}
Register it somewhere:
qmlRegisterType<FancyEnum>("your.path.here", 1, 0, "FancyEnum");
usage in QML:
ComboBox {
model: FancyEnum { id: myEnum }
textRole: "text"
currentIndex: myEnum.getIndex(backend.selectedPanel) : 0
onActivated: backend.selectedPanel = myEnum.getValue(index) }
}
thanks a lot for the answer. i tried this solution i added the 2 classes, registeres the type on the main.cpp (qmlRegisterType<FancyEnum>("pt.gfe.connector", 1, 0, "FancyEnum");) and the called the model in combobox like you do but doesn't work. Is this tested to work? (in QT version 5.11)
– Nmaster88
Nov 15 at 16:39
You will propably have to capture the retranslate event and "reset" the model so the gui gets notified of the change
– Felix
Nov 16 at 12:15
@Felix how do you suggest doing that?
– Nmaster88
Nov 16 at 12:23
@Nmaster88 This is already used in production code, albeit not with the dynamic translation. Is that what you describe as not working?
– Amfasis
Nov 16 at 13:23
@Amfasis yes, my problem is related with dynamic translation.
– Nmaster88
Nov 16 at 14:10
|
show 2 more comments
up vote
1
down vote
up vote
1
down vote
One option is to add a QAbstracstListModel
which does the translation. I made myself a base class, which can be inherited. This also gives you a lot of flexibility for converting a selected item to a value (in this example I am using int, but you can make it anything), which is connected to a C++ backend (I used backend.selectedPanel
for your example)
<< Edit: See answer of Felix for nice addition of dynamic translation >>
base header:
class baseEnum : public QAbstractListModel
{
Q_OBJECT
public:
virtual int rowCount(const QModelIndex &parent) const = 0;
virtual QVariant data(const QModelIndex &index, int role) const = 0;
QHash<int, QByteArray> roleNames() const;
Q_INVOKABLE int getIndex(int value);
Q_INVOKABLE int getValue(int index);
}
base cpp:
QHash<int, QByteArray> baseEnum::roleNames() const
{
QHash<int, QByteArray> result;
result.insert(Qt::DisplayRole, "text");
result.insert(Qt::UserRole + 1, "value");
return result;
}
int baseEnum::getIndex(int value)
{
for(int i=0;i<rowCount(QModelIndex());++i)
if(data(createIndex(i, 0, nullptr), Qt::UserRole + 1).toInt() == value)
return i;
return -1;
}
int baseEnum::getValue(int index)
{
return data(createIndex(index, 0, nullptr), Qt::UserRole + 1).toInt();
}
derived header:
class FancyEnum : public baseEnum
{
Q_OBJECT
public:
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
};
derived cpp:
int FancyEnum::rowCount(const QModelIndex &parent) const
{
if(!parent.isValid())
return 5;
return 0;
}
QVariant FancyEnum::data(const QModelIndex &index, int role) const
{
switch(index.row())
{
case 0: return role == Qt::DisplayRole ? QVariant(tr("None")) : QVariant(0);
case 1: return role == Qt::DisplayRole ? QVariant(tr("Subpanel")) : QVariant(1);
case 2: return role == Qt::DisplayRole ? QVariant(tr("All")) : QVariant(2);
}
return role == Qt::DisplayRole ? QVariant(QString("<%1>").arg(index.row())) : QVariant(0);
}
Register it somewhere:
qmlRegisterType<FancyEnum>("your.path.here", 1, 0, "FancyEnum");
usage in QML:
ComboBox {
model: FancyEnum { id: myEnum }
textRole: "text"
currentIndex: myEnum.getIndex(backend.selectedPanel) : 0
onActivated: backend.selectedPanel = myEnum.getValue(index) }
}
One option is to add a QAbstracstListModel
which does the translation. I made myself a base class, which can be inherited. This also gives you a lot of flexibility for converting a selected item to a value (in this example I am using int, but you can make it anything), which is connected to a C++ backend (I used backend.selectedPanel
for your example)
<< Edit: See answer of Felix for nice addition of dynamic translation >>
base header:
class baseEnum : public QAbstractListModel
{
Q_OBJECT
public:
virtual int rowCount(const QModelIndex &parent) const = 0;
virtual QVariant data(const QModelIndex &index, int role) const = 0;
QHash<int, QByteArray> roleNames() const;
Q_INVOKABLE int getIndex(int value);
Q_INVOKABLE int getValue(int index);
}
base cpp:
QHash<int, QByteArray> baseEnum::roleNames() const
{
QHash<int, QByteArray> result;
result.insert(Qt::DisplayRole, "text");
result.insert(Qt::UserRole + 1, "value");
return result;
}
int baseEnum::getIndex(int value)
{
for(int i=0;i<rowCount(QModelIndex());++i)
if(data(createIndex(i, 0, nullptr), Qt::UserRole + 1).toInt() == value)
return i;
return -1;
}
int baseEnum::getValue(int index)
{
return data(createIndex(index, 0, nullptr), Qt::UserRole + 1).toInt();
}
derived header:
class FancyEnum : public baseEnum
{
Q_OBJECT
public:
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
};
derived cpp:
int FancyEnum::rowCount(const QModelIndex &parent) const
{
if(!parent.isValid())
return 5;
return 0;
}
QVariant FancyEnum::data(const QModelIndex &index, int role) const
{
switch(index.row())
{
case 0: return role == Qt::DisplayRole ? QVariant(tr("None")) : QVariant(0);
case 1: return role == Qt::DisplayRole ? QVariant(tr("Subpanel")) : QVariant(1);
case 2: return role == Qt::DisplayRole ? QVariant(tr("All")) : QVariant(2);
}
return role == Qt::DisplayRole ? QVariant(QString("<%1>").arg(index.row())) : QVariant(0);
}
Register it somewhere:
qmlRegisterType<FancyEnum>("your.path.here", 1, 0, "FancyEnum");
usage in QML:
ComboBox {
model: FancyEnum { id: myEnum }
textRole: "text"
currentIndex: myEnum.getIndex(backend.selectedPanel) : 0
onActivated: backend.selectedPanel = myEnum.getValue(index) }
}
edited Nov 16 at 13:19
answered Nov 14 at 7:16
Amfasis
434310
434310
thanks a lot for the answer. i tried this solution i added the 2 classes, registeres the type on the main.cpp (qmlRegisterType<FancyEnum>("pt.gfe.connector", 1, 0, "FancyEnum");) and the called the model in combobox like you do but doesn't work. Is this tested to work? (in QT version 5.11)
– Nmaster88
Nov 15 at 16:39
You will propably have to capture the retranslate event and "reset" the model so the gui gets notified of the change
– Felix
Nov 16 at 12:15
@Felix how do you suggest doing that?
– Nmaster88
Nov 16 at 12:23
@Nmaster88 This is already used in production code, albeit not with the dynamic translation. Is that what you describe as not working?
– Amfasis
Nov 16 at 13:23
@Amfasis yes, my problem is related with dynamic translation.
– Nmaster88
Nov 16 at 14:10
|
show 2 more comments
thanks a lot for the answer. i tried this solution i added the 2 classes, registeres the type on the main.cpp (qmlRegisterType<FancyEnum>("pt.gfe.connector", 1, 0, "FancyEnum");) and the called the model in combobox like you do but doesn't work. Is this tested to work? (in QT version 5.11)
– Nmaster88
Nov 15 at 16:39
You will propably have to capture the retranslate event and "reset" the model so the gui gets notified of the change
– Felix
Nov 16 at 12:15
@Felix how do you suggest doing that?
– Nmaster88
Nov 16 at 12:23
@Nmaster88 This is already used in production code, albeit not with the dynamic translation. Is that what you describe as not working?
– Amfasis
Nov 16 at 13:23
@Amfasis yes, my problem is related with dynamic translation.
– Nmaster88
Nov 16 at 14:10
thanks a lot for the answer. i tried this solution i added the 2 classes, registeres the type on the main.cpp (qmlRegisterType<FancyEnum>("pt.gfe.connector", 1, 0, "FancyEnum");) and the called the model in combobox like you do but doesn't work. Is this tested to work? (in QT version 5.11)
– Nmaster88
Nov 15 at 16:39
thanks a lot for the answer. i tried this solution i added the 2 classes, registeres the type on the main.cpp (qmlRegisterType<FancyEnum>("pt.gfe.connector", 1, 0, "FancyEnum");) and the called the model in combobox like you do but doesn't work. Is this tested to work? (in QT version 5.11)
– Nmaster88
Nov 15 at 16:39
You will propably have to capture the retranslate event and "reset" the model so the gui gets notified of the change
– Felix
Nov 16 at 12:15
You will propably have to capture the retranslate event and "reset" the model so the gui gets notified of the change
– Felix
Nov 16 at 12:15
@Felix how do you suggest doing that?
– Nmaster88
Nov 16 at 12:23
@Felix how do you suggest doing that?
– Nmaster88
Nov 16 at 12:23
@Nmaster88 This is already used in production code, albeit not with the dynamic translation. Is that what you describe as not working?
– Amfasis
Nov 16 at 13:23
@Nmaster88 This is already used in production code, albeit not with the dynamic translation. Is that what you describe as not working?
– Amfasis
Nov 16 at 13:23
@Amfasis yes, my problem is related with dynamic translation.
– Nmaster88
Nov 16 at 14:10
@Amfasis yes, my problem is related with dynamic translation.
– Nmaster88
Nov 16 at 14:10
|
show 2 more comments
up vote
1
down vote
This is an addition to @Amfasis answer. It extends the very useful "baseEnum" model by adding the capability to detect and react to restranslation events
For the GUI to actually detect that the text was changed after a restranslation, the model must "notify" the gui that data has changed. However, to do that, the model must know when data changed. Thankfully, Qt has the LanguageChange event to do so. The following code catches that event and uses it to notify the gui of the data change.
// in the header file:
class baseEnum : public QAbstractListModel
{
Q_OBJECT
public:
// ... all the stuff from before
bool event(QEvent *event);
};
// and in the cpp file:
bool baseEnum::event(QEvent *ev)
{
if(ev) {
switch(ev->type()) {
case QEvent::LanguageChange:
// notifiy models that the display data has changed for all rows
emit dataChanged(index(0),
index(rowCount(QModelIndex{}) - 1),
{Qt::DisplayRole});
break;
}
}
return QAbstractListModel::event(ev);
}
thanks for this addition :-D I will actually also start using it in my projects :thumbsup:
– Amfasis
Nov 16 at 13:18
@Felix i've added those function to baseEnum class, but rowCount() is not defined there, it's on fancyEnum, how do i call that function? thanks
– Nmaster88
Nov 16 at 14:50
It is declared as pure virtual function and implemented in the FancyEnum model. You can still call it from the base class just like any other normal method
– Felix
Nov 16 at 17:51
@Nmaster88 I also got an error, needed to putrowCount(QModelIndx())
instead. Alsoevent(QEvent*)
is expected to have a bool return value in my version of Qt, not sure if it was changed
– Amfasis
yesterday
Ah yes, I simply screwed up the bool part. Also, InQAbstractListModel
, rowCount is declared asint rowCount(const QModelIndex &parent = QModelIndex()) const
- which is why you can call it without a parameter normally - but as I can see now, in @Amfasis answer he did not specify the default argument again. I will update my answer accordingly
– Felix
yesterday
add a comment |
up vote
1
down vote
This is an addition to @Amfasis answer. It extends the very useful "baseEnum" model by adding the capability to detect and react to restranslation events
For the GUI to actually detect that the text was changed after a restranslation, the model must "notify" the gui that data has changed. However, to do that, the model must know when data changed. Thankfully, Qt has the LanguageChange event to do so. The following code catches that event and uses it to notify the gui of the data change.
// in the header file:
class baseEnum : public QAbstractListModel
{
Q_OBJECT
public:
// ... all the stuff from before
bool event(QEvent *event);
};
// and in the cpp file:
bool baseEnum::event(QEvent *ev)
{
if(ev) {
switch(ev->type()) {
case QEvent::LanguageChange:
// notifiy models that the display data has changed for all rows
emit dataChanged(index(0),
index(rowCount(QModelIndex{}) - 1),
{Qt::DisplayRole});
break;
}
}
return QAbstractListModel::event(ev);
}
thanks for this addition :-D I will actually also start using it in my projects :thumbsup:
– Amfasis
Nov 16 at 13:18
@Felix i've added those function to baseEnum class, but rowCount() is not defined there, it's on fancyEnum, how do i call that function? thanks
– Nmaster88
Nov 16 at 14:50
It is declared as pure virtual function and implemented in the FancyEnum model. You can still call it from the base class just like any other normal method
– Felix
Nov 16 at 17:51
@Nmaster88 I also got an error, needed to putrowCount(QModelIndx())
instead. Alsoevent(QEvent*)
is expected to have a bool return value in my version of Qt, not sure if it was changed
– Amfasis
yesterday
Ah yes, I simply screwed up the bool part. Also, InQAbstractListModel
, rowCount is declared asint rowCount(const QModelIndex &parent = QModelIndex()) const
- which is why you can call it without a parameter normally - but as I can see now, in @Amfasis answer he did not specify the default argument again. I will update my answer accordingly
– Felix
yesterday
add a comment |
up vote
1
down vote
up vote
1
down vote
This is an addition to @Amfasis answer. It extends the very useful "baseEnum" model by adding the capability to detect and react to restranslation events
For the GUI to actually detect that the text was changed after a restranslation, the model must "notify" the gui that data has changed. However, to do that, the model must know when data changed. Thankfully, Qt has the LanguageChange event to do so. The following code catches that event and uses it to notify the gui of the data change.
// in the header file:
class baseEnum : public QAbstractListModel
{
Q_OBJECT
public:
// ... all the stuff from before
bool event(QEvent *event);
};
// and in the cpp file:
bool baseEnum::event(QEvent *ev)
{
if(ev) {
switch(ev->type()) {
case QEvent::LanguageChange:
// notifiy models that the display data has changed for all rows
emit dataChanged(index(0),
index(rowCount(QModelIndex{}) - 1),
{Qt::DisplayRole});
break;
}
}
return QAbstractListModel::event(ev);
}
This is an addition to @Amfasis answer. It extends the very useful "baseEnum" model by adding the capability to detect and react to restranslation events
For the GUI to actually detect that the text was changed after a restranslation, the model must "notify" the gui that data has changed. However, to do that, the model must know when data changed. Thankfully, Qt has the LanguageChange event to do so. The following code catches that event and uses it to notify the gui of the data change.
// in the header file:
class baseEnum : public QAbstractListModel
{
Q_OBJECT
public:
// ... all the stuff from before
bool event(QEvent *event);
};
// and in the cpp file:
bool baseEnum::event(QEvent *ev)
{
if(ev) {
switch(ev->type()) {
case QEvent::LanguageChange:
// notifiy models that the display data has changed for all rows
emit dataChanged(index(0),
index(rowCount(QModelIndex{}) - 1),
{Qt::DisplayRole});
break;
}
}
return QAbstractListModel::event(ev);
}
edited yesterday
answered Nov 16 at 13:08
Felix
4,27111636
4,27111636
thanks for this addition :-D I will actually also start using it in my projects :thumbsup:
– Amfasis
Nov 16 at 13:18
@Felix i've added those function to baseEnum class, but rowCount() is not defined there, it's on fancyEnum, how do i call that function? thanks
– Nmaster88
Nov 16 at 14:50
It is declared as pure virtual function and implemented in the FancyEnum model. You can still call it from the base class just like any other normal method
– Felix
Nov 16 at 17:51
@Nmaster88 I also got an error, needed to putrowCount(QModelIndx())
instead. Alsoevent(QEvent*)
is expected to have a bool return value in my version of Qt, not sure if it was changed
– Amfasis
yesterday
Ah yes, I simply screwed up the bool part. Also, InQAbstractListModel
, rowCount is declared asint rowCount(const QModelIndex &parent = QModelIndex()) const
- which is why you can call it without a parameter normally - but as I can see now, in @Amfasis answer he did not specify the default argument again. I will update my answer accordingly
– Felix
yesterday
add a comment |
thanks for this addition :-D I will actually also start using it in my projects :thumbsup:
– Amfasis
Nov 16 at 13:18
@Felix i've added those function to baseEnum class, but rowCount() is not defined there, it's on fancyEnum, how do i call that function? thanks
– Nmaster88
Nov 16 at 14:50
It is declared as pure virtual function and implemented in the FancyEnum model. You can still call it from the base class just like any other normal method
– Felix
Nov 16 at 17:51
@Nmaster88 I also got an error, needed to putrowCount(QModelIndx())
instead. Alsoevent(QEvent*)
is expected to have a bool return value in my version of Qt, not sure if it was changed
– Amfasis
yesterday
Ah yes, I simply screwed up the bool part. Also, InQAbstractListModel
, rowCount is declared asint rowCount(const QModelIndex &parent = QModelIndex()) const
- which is why you can call it without a parameter normally - but as I can see now, in @Amfasis answer he did not specify the default argument again. I will update my answer accordingly
– Felix
yesterday
thanks for this addition :-D I will actually also start using it in my projects :thumbsup:
– Amfasis
Nov 16 at 13:18
thanks for this addition :-D I will actually also start using it in my projects :thumbsup:
– Amfasis
Nov 16 at 13:18
@Felix i've added those function to baseEnum class, but rowCount() is not defined there, it's on fancyEnum, how do i call that function? thanks
– Nmaster88
Nov 16 at 14:50
@Felix i've added those function to baseEnum class, but rowCount() is not defined there, it's on fancyEnum, how do i call that function? thanks
– Nmaster88
Nov 16 at 14:50
It is declared as pure virtual function and implemented in the FancyEnum model. You can still call it from the base class just like any other normal method
– Felix
Nov 16 at 17:51
It is declared as pure virtual function and implemented in the FancyEnum model. You can still call it from the base class just like any other normal method
– Felix
Nov 16 at 17:51
@Nmaster88 I also got an error, needed to put
rowCount(QModelIndx())
instead. Also event(QEvent*)
is expected to have a bool return value in my version of Qt, not sure if it was changed– Amfasis
yesterday
@Nmaster88 I also got an error, needed to put
rowCount(QModelIndx())
instead. Also event(QEvent*)
is expected to have a bool return value in my version of Qt, not sure if it was changed– Amfasis
yesterday
Ah yes, I simply screwed up the bool part. Also, In
QAbstractListModel
, rowCount is declared as int rowCount(const QModelIndex &parent = QModelIndex()) const
- which is why you can call it without a parameter normally - but as I can see now, in @Amfasis answer he did not specify the default argument again. I will update my answer accordingly– Felix
yesterday
Ah yes, I simply screwed up the bool part. Also, In
QAbstractListModel
, rowCount is declared as int rowCount(const QModelIndex &parent = QModelIndex()) const
- which is why you can call it without a parameter normally - but as I can see now, in @Amfasis answer he did not specify the default argument again. I will update my answer accordingly– Felix
yesterday
add a comment |
up vote
0
down vote
Unfortunately, I can't test all the cases at the moment (and I don't have an access to the Qt 5.11.2), but I think this should work:
ComboBox {
textRole: "text"
Layout.fillWidth: true
displayText: qsTr(currentText)
model: ListModel {
ListElement{text: "None"}
ListElement{text: "Subpanel"}
ListElement{text: "All"}
}
delegate: Button {
width: ListView.view.width
text: qsTr(model.text)
}
}
Or, another way is to re-create a model when language is changed:
ComboBox {
id: combobox
textRole: "text"
Layout.fillWidth: true
model: ListModel {
dynamicRoles: true
}
Component.onCompleted: {
reload()
}
Connections {
target: trans // this is a translator from a git project you are referring to
onLanguageChanged: {
combobox.reload()
}
}
function reload() {
var i = combobox.currentIndex
combobox.model = [
{text: qsTr("None")},
{text: qsTr("Subpanel")},
{text: qsTr("All")}
]
combobox.currentIndex = i
}
}
In the first example you need to useQT_TR_NOOP
in theListModel
so thatlupdate
knows there is a string to be translated
– Amfasis
2 days ago
@Amfasis, could you please clarify why do I need to use it?
– Andrii
yesterday
The tool that searches for text that should be translated (lupdate
) does not look through if there is a variable in theqsTr(...)
call, so it will not translate the three items in yourListModel
(ok, there is a chance it will find the same text already translated and use that, but that's not good programming IMHO)
– Amfasis
yesterday
got it, thank you
– Andrii
yesterday
add a comment |
up vote
0
down vote
Unfortunately, I can't test all the cases at the moment (and I don't have an access to the Qt 5.11.2), but I think this should work:
ComboBox {
textRole: "text"
Layout.fillWidth: true
displayText: qsTr(currentText)
model: ListModel {
ListElement{text: "None"}
ListElement{text: "Subpanel"}
ListElement{text: "All"}
}
delegate: Button {
width: ListView.view.width
text: qsTr(model.text)
}
}
Or, another way is to re-create a model when language is changed:
ComboBox {
id: combobox
textRole: "text"
Layout.fillWidth: true
model: ListModel {
dynamicRoles: true
}
Component.onCompleted: {
reload()
}
Connections {
target: trans // this is a translator from a git project you are referring to
onLanguageChanged: {
combobox.reload()
}
}
function reload() {
var i = combobox.currentIndex
combobox.model = [
{text: qsTr("None")},
{text: qsTr("Subpanel")},
{text: qsTr("All")}
]
combobox.currentIndex = i
}
}
In the first example you need to useQT_TR_NOOP
in theListModel
so thatlupdate
knows there is a string to be translated
– Amfasis
2 days ago
@Amfasis, could you please clarify why do I need to use it?
– Andrii
yesterday
The tool that searches for text that should be translated (lupdate
) does not look through if there is a variable in theqsTr(...)
call, so it will not translate the three items in yourListModel
(ok, there is a chance it will find the same text already translated and use that, but that's not good programming IMHO)
– Amfasis
yesterday
got it, thank you
– Andrii
yesterday
add a comment |
up vote
0
down vote
up vote
0
down vote
Unfortunately, I can't test all the cases at the moment (and I don't have an access to the Qt 5.11.2), but I think this should work:
ComboBox {
textRole: "text"
Layout.fillWidth: true
displayText: qsTr(currentText)
model: ListModel {
ListElement{text: "None"}
ListElement{text: "Subpanel"}
ListElement{text: "All"}
}
delegate: Button {
width: ListView.view.width
text: qsTr(model.text)
}
}
Or, another way is to re-create a model when language is changed:
ComboBox {
id: combobox
textRole: "text"
Layout.fillWidth: true
model: ListModel {
dynamicRoles: true
}
Component.onCompleted: {
reload()
}
Connections {
target: trans // this is a translator from a git project you are referring to
onLanguageChanged: {
combobox.reload()
}
}
function reload() {
var i = combobox.currentIndex
combobox.model = [
{text: qsTr("None")},
{text: qsTr("Subpanel")},
{text: qsTr("All")}
]
combobox.currentIndex = i
}
}
Unfortunately, I can't test all the cases at the moment (and I don't have an access to the Qt 5.11.2), but I think this should work:
ComboBox {
textRole: "text"
Layout.fillWidth: true
displayText: qsTr(currentText)
model: ListModel {
ListElement{text: "None"}
ListElement{text: "Subpanel"}
ListElement{text: "All"}
}
delegate: Button {
width: ListView.view.width
text: qsTr(model.text)
}
}
Or, another way is to re-create a model when language is changed:
ComboBox {
id: combobox
textRole: "text"
Layout.fillWidth: true
model: ListModel {
dynamicRoles: true
}
Component.onCompleted: {
reload()
}
Connections {
target: trans // this is a translator from a git project you are referring to
onLanguageChanged: {
combobox.reload()
}
}
function reload() {
var i = combobox.currentIndex
combobox.model = [
{text: qsTr("None")},
{text: qsTr("Subpanel")},
{text: qsTr("All")}
]
combobox.currentIndex = i
}
}
edited Nov 16 at 15:20
answered Nov 16 at 15:11
Andrii
1,251916
1,251916
In the first example you need to useQT_TR_NOOP
in theListModel
so thatlupdate
knows there is a string to be translated
– Amfasis
2 days ago
@Amfasis, could you please clarify why do I need to use it?
– Andrii
yesterday
The tool that searches for text that should be translated (lupdate
) does not look through if there is a variable in theqsTr(...)
call, so it will not translate the three items in yourListModel
(ok, there is a chance it will find the same text already translated and use that, but that's not good programming IMHO)
– Amfasis
yesterday
got it, thank you
– Andrii
yesterday
add a comment |
In the first example you need to useQT_TR_NOOP
in theListModel
so thatlupdate
knows there is a string to be translated
– Amfasis
2 days ago
@Amfasis, could you please clarify why do I need to use it?
– Andrii
yesterday
The tool that searches for text that should be translated (lupdate
) does not look through if there is a variable in theqsTr(...)
call, so it will not translate the three items in yourListModel
(ok, there is a chance it will find the same text already translated and use that, but that's not good programming IMHO)
– Amfasis
yesterday
got it, thank you
– Andrii
yesterday
In the first example you need to use
QT_TR_NOOP
in the ListModel
so that lupdate
knows there is a string to be translated– Amfasis
2 days ago
In the first example you need to use
QT_TR_NOOP
in the ListModel
so that lupdate
knows there is a string to be translated– Amfasis
2 days ago
@Amfasis, could you please clarify why do I need to use it?
– Andrii
yesterday
@Amfasis, could you please clarify why do I need to use it?
– Andrii
yesterday
The tool that searches for text that should be translated (
lupdate
) does not look through if there is a variable in the qsTr(...)
call, so it will not translate the three items in your ListModel
(ok, there is a chance it will find the same text already translated and use that, but that's not good programming IMHO)– Amfasis
yesterday
The tool that searches for text that should be translated (
lupdate
) does not look through if there is a variable in the qsTr(...)
call, so it will not translate the three items in your ListModel
(ok, there is a chance it will find the same text already translated and use that, but that's not good programming IMHO)– Amfasis
yesterday
got it, thank you
– Andrii
yesterday
got it, thank you
– Andrii
yesterday
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53277684%2fdynamic-translation-of-combobox-qml%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Create hidden
Label
s and define the texts there. Then let the list elements bind to those labels. That could work– Felix
Nov 13 at 9:50
Or create a QAbstractListModel with your texts, this way you can even tie a certain value to a certain text
– Amfasis
Nov 13 at 10:10
@Felix that doesnt work.
– Nmaster88
Nov 13 at 15:45
@Amfasis can you give an example on how i can do that? thanks
– Nmaster88
Nov 13 at 15:45