QLineEdit should accept hexadecimal values ranging from [0 - FFFFF] - qt

I have a requirement where I want my QLineEdit should accept hexadecimal values ranging from [0 - FFFFF]. can someone help me out with this?
I have tried the below code, but it holds good for only 1 char display.

I don't see any code in your post, but what you're looking for is a validator, derived from the QValidator class. Create a sub-class, say HexValidator, and implement the "validate" method. You check the input string for the allowed characters and range and return the appropriate state.
You then assign the validator to the QLineEdit using the QLineEdit::setValidator method. Note that the QLineEdit doesn't take ownership of the validator, so you need to make sure you delete it separately or give it a parent so that it gets cleaned up when the parent is deleted. You can create a single validator and assign it to multiple fields if needed.

I was wrong in my comment about Qt docs having a Hex spin box example... so I found one in my archive instead. It could be more flexible, but OTOH it's very simple and short. I know this isn't a QLineEdit but maybe it'll help anyway. The QValidator used here could be used in a line edit also.
#ifndef _HEXSPINBOX_H_
#define _HEXSPINBOX_H_
#include <QSpinBox>
#include <QRegularExpressionValidator>
// NOTE: Since QSpinBox uses int as the storage type, the effective editing range
// is +/- 0x7FFF FFFF, so it can't handle a full unsigned int.
// QDoubleSpinBox would be a more suitable base class if a wider range is needed.
class HexSpinBox : public QSpinBox
{
Q_OBJECT
public:
HexSpinBox(QWidget *parent = nullptr,
bool showPrefix = false,
const QString &format = QStringLiteral("%x")) :
QSpinBox(parent),
format(format)
{
// Validates hex strings up to 8 chars with or w/out leading "0x" prefix.
// For arbitrary prefix/suffix, the regex could be built dynamically
// in validate(), or override setPrefix()/setSuffix() methods.
const QRegularExpression rx("(?:0[xX])?[0-9A-Fa-f]{1,8}");
validator = new QRegularExpressionValidator(rx, this);
setShowPrefix(showPrefix);
}
public slots:
void setShowPrefix(bool show)
{
if (show)
setPrefix(QStringLiteral("0x"));
else
setPrefix(QString());
}
void setFormat(const QString &text)
{
format = text;
lineEdit()->setText(textFromValue(value()));
}
protected:
QValidator::State validate(QString &text, int &pos) const override
{
return validator->validate(text, pos);
}
int valueFromText(const QString &text) const override
{
return text.toInt(0, 16);
}
QString textFromValue(int value) const override
{
return QString().sprintf(qPrintable(format), value);
}
private:
QRegularExpressionValidator *validator;
QString format;
};
#endif // _HEXSPINBOX_H_
Example:
#include "HexSpinBox.h"
#include <QApplication>
#include <QBoxLayout>
#include <QDialog>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDialog d;
d.setLayout(new QVBoxLayout);
HexSpinBox* sb = new HexSpinBox(&d);
sb->setMaximum(0xFFFFF);
sb->setValue(0x0A234);
d.layout()->addWidget(sb);
HexSpinBox* sb2 = new HexSpinBox(&d, true, QStringLiteral("%05X"));
sb2->setMaximum(0xFFFFF);
sb2->setValue(0x0A234);
d.layout()->addWidget(sb2);
return d.exec();
}

Related

Change QSortFilterProxyModel behaviour for multiple column filtering

We have a QSortFilterProxyModel installed on a QTableView and two (or more) QLineEdit for filtering the view (based on the text of these QLineEdits)
In our view we have a slot that tells us the string of lineedits and the current column that we want. Something like this :
void onTextChange(int index, QString ntext) {
filter.setFilterKeyColumn(index);
filter.setFilterRegExp(QRegExp(ntext, Qt::CaseInsensitive));
}
On the first column we have names in the second we have year of birthday.
Now we enter a year for column 2 (for example 1985). Until now filtering is ok but when we switch to the first lineedit and enter a name (for example john) the previous filtering based on year will reset.
How could we change this behaviour for our custom QSortFilterProxyModel ?
(Actually when we change the filter keycolumn the filtermodel must filter existing view not reset it)
Update...
Based on #Mike's answer :
If you interacting with unknown column count using QMap<int, QRegExp> will help you
You can subclass QSortFilterProxyModel, to make it take two separate filters (one for the name and the other for the year), and override filterAcceptsRow to return true only when both filters are satisfied.
The Qt documentation's Custom Sort/Filter Model Example shows a subclassed QSortFilterProxyModel that can take filters for dates in addition to the main string filter used for searching.
Here is a fully working example on how to make a subclassed QSortFilterProxyModel apply two separate filters for one table:
#include <QApplication>
#include <QtWidgets>
class NameYearFilterProxyModel : public QSortFilterProxyModel{
Q_OBJECT
public:
explicit NameYearFilterProxyModel(QObject* parent= nullptr):
QSortFilterProxyModel(parent){
//general parameters for the custom model
nameRegExp.setCaseSensitivity(Qt::CaseInsensitive);
yearRegExp.setCaseSensitivity(Qt::CaseInsensitive);
yearRegExp.setPatternSyntax(QRegExp::RegExp);
nameRegExp.setPatternSyntax(QRegExp::RegExp);
}
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override{
QModelIndex nameIndex= sourceModel()->index(sourceRow, 0, sourceParent);
QModelIndex yearIndex= sourceModel()->index(sourceRow, 1, sourceParent);
QString name= sourceModel()->data(nameIndex).toString();
QString year= sourceModel()->data(yearIndex).toString();
return (name.contains(nameRegExp) && year.contains(yearRegExp));
}
public slots:
void setNameFilter(const QString& regExp){
nameRegExp.setPattern(regExp);
invalidateFilter();
}
void setYearFilter(const QString& regExp){
yearRegExp.setPattern(regExp);
invalidateFilter();
}
private:
QRegExp nameRegExp;
QRegExp yearRegExp;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//set up GUI
QWidget w;
QVBoxLayout layout(&w);
QHBoxLayout hLayout;
QLineEdit lineEditName;
QLineEdit lineEditYear;
lineEditName.setPlaceholderText("name filter");
lineEditYear.setPlaceholderText("year filter");
lineEditYear.setValidator(new QRegExpValidator(QRegExp("[0-9]*")));
lineEditYear.setMaxLength(4);
hLayout.addWidget(&lineEditName);
hLayout.addWidget(&lineEditYear);
QTableView tableView;
layout.addLayout(&hLayout);
layout.addWidget(&tableView);
//set up models
QStandardItemModel sourceModel;
NameYearFilterProxyModel filterModel;;
filterModel.setSourceModel(&sourceModel);
tableView.setModel(&filterModel);
QObject::connect(&lineEditName, &QLineEdit::textChanged,
&filterModel, &NameYearFilterProxyModel::setNameFilter);
QObject::connect(&lineEditYear, &QLineEdit::textChanged,
&filterModel, &NameYearFilterProxyModel::setYearFilter);
//fill with dummy data
QVector<QString> names{"Danny", "Christine", "Lars",
"Roberto", "Maria"};
for(int i=0; i<100; i++){
QList<QStandardItem*> row;
row.append(new QStandardItem(names[i%names.size()]));
row.append(new QStandardItem(QString::number((i%9)+1980)));
sourceModel.appendRow(row);
}
w.show();
return a.exec();
}
#include "main.moc"
Based on #Hayt's answer and comment. Since you want to have two separate filters on your model, You can have two chained QSortFilterProxyModel(one does the filtering based on the name, and the other does the filtering based on the year using the first filtering model as the source model).
Here is a fully working example on how to have two separate filters for one table:
#include <QApplication>
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//set up GUI
QWidget w;
QVBoxLayout layout(&w);
QHBoxLayout hLayout;
QLineEdit lineEditName;
QLineEdit lineEditYear;
lineEditName.setPlaceholderText("name filter");
lineEditYear.setPlaceholderText("year filter");
lineEditYear.setValidator(new QRegExpValidator(QRegExp("[0-9]*")));
lineEditYear.setMaxLength(4);
hLayout.addWidget(&lineEditName);
hLayout.addWidget(&lineEditYear);
QTableView tableView;
layout.addLayout(&hLayout);
layout.addWidget(&tableView);
//set up models
QStandardItemModel sourceModel;
QSortFilterProxyModel yearFilterModel;
yearFilterModel.setSourceModel(&sourceModel);
QSortFilterProxyModel nameFilterModel;
//nameFilterModel uses yearFilterModel as source
nameFilterModel.setSourceModel(&yearFilterModel);
//tableView displayes the last model in the chain nameFilterModel
tableView.setModel(&nameFilterModel);
nameFilterModel.setFilterKeyColumn(0);
yearFilterModel.setFilterKeyColumn(1);
nameFilterModel.setFilterCaseSensitivity(Qt::CaseInsensitive);
yearFilterModel.setFilterCaseSensitivity(Qt::CaseInsensitive);
QObject::connect(&lineEditName, &QLineEdit::textChanged, &nameFilterModel,
static_cast<void (QSortFilterProxyModel::*)(const QString&)>
(&QSortFilterProxyModel::setFilterRegExp));
QObject::connect(&lineEditYear, &QLineEdit::textChanged, &yearFilterModel,
static_cast<void (QSortFilterProxyModel::*)(const QString&)>
(&QSortFilterProxyModel::setFilterRegExp));
//fill with dummy data
QVector<QString> names{"Danny", "Christine", "Lars",
"Roberto", "Maria"};
for(int i=0; i<100; i++){
QList<QStandardItem*> row;
row.append(new QStandardItem(names[i%names.size()]));
row.append(new QStandardItem(QString::number((i%9)+1980)));
sourceModel.appendRow(row);
}
w.show();
return a.exec();
}
If you want to connect the 2 inputs with a "and" filter you can simply layer them.
Something like this should work.
QSortFilterProxyModel namefilter;
nameFilter.setFilterKeyColumn(nameColum);
QSortFilterProxyModel yearFilter;
yearFilter.setFilterKeyColumn(yearColumn);
yearFilter.setSourceModel(model);
nameFilter.setSourceModel(&yearFilter);
view.setSource(&nameFilter);
//....
void onTextChange(int index, QString ntext)
{
switch(index)
{
case yearColumn:
yearFilter.setFilterRegExp(QRegExp(ntext, Qt::CaseInsensitive));
break;
case nameColum:
namefilter.setFilterRegExp(QRegExp(ntext, Qt::CaseInsensitive));
break;
}
}
I know this is an old thread, but here is a more generic version of the QSortFilterProxyModel with a multicolumn filter implementation. I saw someone's comment (Mike) that eluded to a solution like this, but I didn't see any code examples for it.
This design allows you to indicate weather the model is multifilter when creating an SortFilterProxyModel object. The reason for this is so that you can add other custom behavior without having to create a separate QSortFilterProxyModel subclass. In other words, if you create other custom behaviors by overriding QSortFilterProxyModel functions in this manner, you can pick and choose which custom sort/filter behaviors you want, and which standard sort/filter behaviors you want, for a given object. Obviously if you don't need or want that kind of flexibility with your subclass you can make it your own with a few small adjustments.
Header:
class SortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit SortFilterProxyModel(bool multiFilterModel, QObject *parent = nullptr);
void setMultiFilterRegularExpression(const int &column, const QString &pattern);
void clearMultiFilter();
protected:
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
private:
QMap<int, QRegularExpression> m_multiFilterMap;
bool m_multiFilterModel = false;
signals:
};
Implementation:
#include "sortfilterproxymodel.h"
//The constructor takes one additional argument (multiFilterModel) that
//will dictate filtering behavior. If multiFilterModel is false the
//setMultiFilterRegularExpression and clearMultifilter will do nothing.
SortFilterProxyModel::SortFilterProxyModel(bool multiFilterModel, QObject *parent) : QSortFilterProxyModel(parent)
{
m_multiFilterModel = multiFilterModel;
}
//This loads the QMap with the column numbers and their corresponding filters.
//This member function that should be called from your main to filter model.
void SortFilterProxyModel::setMultiFilterRegularExpression(const int &column, const QString &pattern)
{
if(!m_multiFilterModel) //notifying that this does nothing and returning
{
qDebug() << "Object is not a multiFilterModel!";
return;
}
QRegularExpression filter;
filter.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
filter.setPattern(pattern);
m_multiFilterMap.insert(column, filter);
invalidateFilter(); //this causes filterAcceptsRow to run
}
//This will effectively unfilter the model by making the pattern for all
//existing regular expressions in the QMap to an empty string, and then invalidating the filter.
//This member function should be called from main to clear filter.
void SortFilterProxyModel::clearMultiFilter()
{
if(!m_multiFilterModel) //notifying that this does nothing and returning
{
qDebug() << "Object is not a multiFilterModel!";
return;
}
QMap<int, QRegularExpression>::const_iterator i = m_multiFilterMap.constBegin();
while(i != m_multiFilterMap.constEnd())
{
QRegularExpression blankExpression("");
m_multiFilterMap.insert(i.key(), blankExpression);
i++;
}
invalidateFilter(); //this causes filterAcceptsRow to run
}
//This checks to see if the model should be multifiltered, else it will
//work like the standard QSortFilterProxyModel.
bool SortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if(m_multiFilterModel)
{
QMap<int, QRegularExpression>::const_iterator i = m_multiFilterMap.constBegin();
while(i != m_multiFilterMap.constEnd())
{
QModelIndex index = sourceModel()->index(source_row, i.key(), source_parent);
QString indexValue = sourceModel()->data(index).toString();
if(!indexValue.contains(i.value()))
{
return false; //if a value doesn't match returns false
}
i++;
}
return true; //if all column values match returns true
}
//This is standard QSortFilterProxyModel behavoir. It only runs if object is not multiFilterModel
QModelIndex index = sourceModel()->index(source_row, filterKeyColumn(), source_parent);
QString indexValue = sourceModel()->data(index).toString();
return indexValue.contains(filterRegularExpression());
}

Disable specific items in QComboBox

In my application, I want to disable some items (i.e. not selectable, no highlights when mouse hovering above, and the texts are greyed out) in the QComboBox when certain conditions are met.
I indeed found someone did ask the same question here: Disable Item in Qt Combobox
But none of these solutions in the answers seem to actually work (including the trick).
Is there a decent and 'correct' way to implement this?
EDIT:
I found out why setting the flags wouldn't disable the items in my application: for some reasons, I had to set the style QStyle::SH_ComboBox_UseNativePopup(see https://codereview.qt-project.org/#/c/82718/). And this setting for some reasons blocked the flag setting. Does anyone have an idea why, and how to work around? A minimum test example is included (modified from the answer of #Mike):
#include <QApplication>
#include <QComboBox>
#include <QStandardItemModel>
#include <QProxyStyle>
class ComboBoxStyle : public QProxyStyle
{
public:
int styleHint ( StyleHint hint, const QStyleOption * option = 0, const QWidget * widget = 0, QStyleHintReturn * returnData = 0 ) const override
{
if ( hint == QStyle::SH_ComboBox_UseNativePopup )
{
return 1;
}
return QProxyStyle::styleHint( hint, option, widget, returnData );
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QComboBox comboBox;
// Setting this style would block the flag settings later on.
comboBox.setStyle( new ComboBoxStyle() );
comboBox.insertItem(0, QObject::tr("item1"));
comboBox.insertItem(1, QObject::tr("item2"));
QStandardItemModel* model = qobject_cast<QStandardItemModel*>(comboBox.model());
QStandardItem* item= model->item(1);
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
comboBox.show();
return a.exec();
}
The answer linked in my comment above seems to be talking about an old version of Qt. I have tested on Qt5.4 and Qt5.6 and there is no need set the color yourself here, you just need to set and/or clear the Qt::ItemIsEnabled flag, here is an example:
#include <QtWidgets>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QComboBox comboBox;
comboBox.addItem(QObject::tr("item1"));
comboBox.addItem(QObject::tr("item2"));
comboBox.addItem(QObject::tr("item3"));
QStandardItemModel *model =
qobject_cast<QStandardItemModel *>(comboBox.model());
Q_ASSERT(model != nullptr);
bool disabled = true;
QStandardItem *item = model->item(2);
item->setFlags(disabled ? item->flags() & ~Qt::ItemIsEnabled
: item->flags() | Qt::ItemIsEnabled);
comboBox.show();
return a.exec();
}
Here is the technique #Mike describes, wrapped up in a convenient utility function:
void SetComboBoxItemEnabled(QComboBox * comboBox, int index, bool enabled)
{
auto * model = qobject_cast<QStandardItemModel*>(comboBox->model());
assert(model);
if(!model) return;
auto * item = model->item(index);
assert(item);
if(!item) return;
item->setEnabled(enabled);
}

Disable validation in QSpinBox

Hence I have a QSpinBox, and want to unset validation for writing not only int values, but also string in it.
Please help me to fix this.
I have tried this, but it does not work:
class Spinbox:public QSpinBox
{
public:
Spinbox(QWidget* parent=0)
:QSpinBox(parent){}
void setLineEdit(QLineEdit *l)
{
QSpinBox::setLineEdit(l);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Spinbox de;
QLineEdit le;
le.setValidator(0);
le.setText("text");
de.setLineEdit(&le);
de.show();
return a.exec();
}
Qt docs say that:
If QLineEdit::validator() for the lineEdit returns 0, the internal
validator of the spinbox will be set on the line edit.
Thus, in order to disable the QSpinBox's built in validator, you need to set your own (dummy?). I.e.
class Validator : public QValidator
{
public:
State validate(QString &input, int &pos ) const
{
return QValidator::Acceptable;
}
};
[..]
Spinbox de;
QLineEdit le;
le.setValidator(new Validator());
le.setText("text");
de.setLineEdit(&le);
de.show();

Can a QDeclarativeListProperty be accessed directly, instead of as a model?

I'm trying to use a QDeclarativeListProperty in order to manage a list of parameters, mostly for the purposes of displaying them in a ListView. However, I would also like to be able to directly access the parameters in QML from the QDeclarativeListProperty so that I can display/modify individual parameters on different screens.
My class is called ParameterClass, for which I've created a QList:
class SystemData : public QObject
{
Q_OBJECT
Q_PROPERTY(QDeclarativeListProperty<ParameterClass> parameters READ parameters CONSTANT)
QDeclarativeListProperty<ParameterClass> parameters();
...
QList<ParameterClass *> m_parameterList;
}
I've also registered the ParameterClass class and set up an instance of my SystemData as a property, which I know is necessary.
m_context->setContextProperty("SystemData", m_pSystemData);
qmlRegisterType<ParameterClass>();
Now, what I want to do within QML is something like this:
Rectangle {
id: frame
property variant parameter: SystemData.parameters[5]
...
}
I'm just not getting it to work: I keep getting back [undefined]. Am I wasting my time, or am I missing something?
Edit:
I've changed things to use the suggestion from ... . Here are some selections from my updated code.
main.cpp:
#include <QApplication>
#include <QSplashScreen>
#include <QLocale>
#include <QLibraryInfo>
#include <QDeclarativeView>
#include <QDeclarativeContext>
#include <QDeclarativeEngine>
#include <QObject>
#include <QDeclarativeListProperty>
#include "systemdata.h"
#include "parameterclass.h"
static const QString contentPath = "qrc:/qml/qml/pk_ui/";
static const QString filename(contentPath + "main.qml");
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QDeclarativeView mainView;
SystemData* systemData = SystemData::getInstance();
QThread thread;
UpdateWorker updateWorker;
QObject::connect((const QObject*)systemData, SIGNAL(startWork()),
(const QObject*)&updateWorker, SLOT(doWork()));
updateWorker.moveToThread(&thread);
thread.start();
systemData->startUpdates();
QFont defaultFont;
defaultFont.setFamily("Sans Serif");
QApplication::setFont(defaultFont);
// Register types to be available in QML
qmlRegisterType<ParameterClass>();
qmlRegisterUncreatableType<SystemEnum>("SystemEnums", 1, 0, "SystemEnum", QString());
mainView.engine()->rootContext()->setContextProperty("SystemData", systemData);
// Set view optimizations not already done for QDeclarativeView
mainView.setResizeMode(QDeclarativeView::SizeRootObjectToView);
mainView.setAttribute(Qt::WA_OpaquePaintEvent);
mainView.setAttribute(Qt::WA_NoSystemBackground);
mainView.setSource(QUrl(filename));
mainView.show();
return app.exec();
}
The ParameterClass looks like this:
class ParameterClass : public QObject
{
Q_OBJECT
Q_PROPERTY(int type READ get_type NOTIFY typeChanged)
Q_PROPERTY(bool enabled READ get_ParameterEnabled WRITE set_ParameterEnabled NOTIFY enabledChanged)
Q_PROPERTY(int groupID READ get_GroupID WRITE set_GroupID NOTIFY groupIDChanged)
Q_PROPERTY(int unitID READ get_UnitID WRITE set_UnitID NOTIFY unitIDChanged)
Q_PROPERTY(int securityLevel READ get_SecurityLevel WRITE set_SecurityLevel NOTIFY securityLevelChanged)
Q_PROPERTY(QString parameterName READ get_ParameterName NOTIFY parameterNameChanged)
Q_PROPERTY(QString shortDescription READ get_ShortDescription NOTIFY shortDescriptionChanged)
Q_PROPERTY(int currentValue READ get_CV WRITE set_valueptrvalue NOTIFY currentValueChanged)
Q_PROPERTY(int lowerBound READ get_LB NOTIFY lowerBoundChanged)
Q_PROPERTY(int upperBound READ get_UB NOTIFY upperBoundChanged)
public:
struct ValueTypes
{
enum
{
IntegerType,
StringType,
StringListType
};
};
ParameterClass(QObject *parent = 0);
int get_type();
bool get_ParameterEnabled();
int get_GroupID();
int get_UnitID();
int get_SecurityLevel();
QString get_ParameterName();
QString get_ShortDescription();
int get_CV() { return *CurrentValuePtr; }
int get_LB() { return *LowerBoundPtr; }
int get_UB() { return *UpperBoundPtr; }
void set_ParameterEnabled(bool InParameterEnabled);
void set_GroupID(int InGroupID);
void set_UnitID(int InUnitID);
void set_SecurityLevel(int InSecurityLevel);
signals:
void typeChanged();
void enabledChanged();
void groupIDChanged();
void unitIDChanged();
void securityLevelChanged();
void parameterNameChanged();
void shortDescriptionChanged();
private:
int type;
bool ParameterEnabled;
int GroupID;
int UnitID;
int SecruityLevel;
QString ParameterName;
QString ShortDescription;
int * CurrentValuePtr;
int * LowerBoundPtr;
int * UpperBoundPtr;
};
And my QML file:
Rectangle {
id: frame
property int val: SystemData.parameters[4].currentValue
...
}
It looks like I'm still getting an undefined value in this case. I'm trying to debug now, so that I can provide more information.
It's very much possible. The key is to make sure you register the QML type and set the context property before setting the source on your QDeclarativeView.
Here's a working example -
main.cpp:
#include <QApplication>
#include <QtDeclarative>
class MyPropertyObject : public QObject {
Q_OBJECT
Q_PROPERTY(int value READ value CONSTANT)
public:
MyPropertyObject(int value = -1) : m_value(value) { }
int value() const {
return m_value;
}
private:
int m_value;
};
class MyObject : public QObject {
Q_OBJECT
Q_PROPERTY(QDeclarativeListProperty<MyPropertyObject> props READ props CONSTANT)
public:
MyObject() {
m_props.append(new MyPropertyObject(55));
m_props.append(new MyPropertyObject(44));
m_props.append(new MyPropertyObject(33));
}
QDeclarativeListProperty<MyPropertyObject> props() {
return QDeclarativeListProperty<MyPropertyObject>(this, m_props);
}
private:
QList<MyPropertyObject *> m_props;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDeclarativeView view;
view.engine()->rootContext()->setContextProperty(QLatin1String("tester"), new MyObject);
qmlRegisterType<MyPropertyObject>();
view.setSource(QUrl("qrc:///qml/main.qml"));
view.setResizeMode(QDeclarativeView::SizeRootObjectToView);
view.resize(300, 300);
view.show();
return a.exec();
}
#include "main.moc"
main.qml:
import QtQuick 1.1
Rectangle {
property variant foo: tester.props[2].value
Text {
anchors.centerIn: parent
text: parent.foo
}
}
Note: read the docs for the QDeclarativeListProperty constructors. The one I'm using for this example is not the preferred one, but is good for quick prototypes.

connecting three comboboxes to control the options avaliable in qt

I have three comboboxes with three similar options, 'one', 'two', 'three', and I want to prevent the same option in different combobox.
Example:
combobox1 : 'one',
so when I go choose in combobox2 and combobox3 there's only 'two' and 'three' to choose from.
I know I could do this in a combination of for loop and if, but can anyone help me with some trick I could use here?
Write your own class MyComboBox which is derived from QComboBox.
Implement a slot in MyComboBox that would do something like this:
void excludeIndex(const QString & text)
{
// Get the list of all the options for the ComboBox
QStringList list = getIndices();
// Remove one (the only) item 'text' from the list
list.removeOne( text );
// Clear the ComboBox and fill with the new values
this->clear();
this->addItems( list );
}
In your parent widget/application, connect the signal void currentIndexChanged(const QString & text) from each 'sending' MyComboBox or QComboBox to this slot of the 'receiving' MyComboBox.
If you need to exclude the values from multiple other ComboBoxes, then it might be better to implement the slot in the parent Widget. That way, you can loop over all the 'receiving' ComboBoxes. Per ComboBox you will read all the current values of the other ComboBoxes and remove those values from list. Your slot in the parent Widget will not need an input QString anymore.
How about using only one combobox? There are only six possible options:
one two three
one three two
two one three
two three one
three one two
three two one
It would be much easier for the user to use only one combobox instead of using three comboboxes whose available options are continuously changing.
Here is one solution.
Basically it initializes all of the boxes with all the items, and as a box's current text is changed, it removes that text from the other boxes. If the previous text that the box contained wasn't blank, it adds it back into all the other boxes.
If you care to test it with more than 8, change the variable m_numOfBoxes in mainwindow.cpp to some other value.
main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QComboBox>
#include <QList>
#include <QStringList>
#include <QMap>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void on_comboBox_changed();
private:
QList <QComboBox *> m_boxes;
QMap <QComboBox *, QString> m_previousText;
int m_numOfBoxes;
QStringList m_allItems;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QVBoxLayout>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QVBoxLayout * vbox = new QVBoxLayout();
m_numOfBoxes = 8;
m_allItems << "";
for(int i = 0; i< m_numOfBoxes; i++)
{
m_allItems << QString::number(i+1);
}
for(int i = 0; i< m_numOfBoxes; i++)
{
QComboBox * temp = new QComboBox;
QObject::connect(temp, SIGNAL(currentIndexChanged(int)), this, SLOT(on_comboBox_changed()));
vbox->addWidget(temp);
temp->addItems(m_allItems);
m_boxes.append(temp);
m_previousText[temp] = "";
}
this->setCentralWidget(new QWidget());
this->centralWidget()->setLayout(vbox);
}
MainWindow::~MainWindow()
{
}
void MainWindow::on_comboBox_changed()
{
QComboBox * editedBox = qobject_cast <QComboBox *> (QObject::sender());
QString currentText = editedBox->currentText();
if(currentText == m_previousText[editedBox])
{
return;
}
foreach(QComboBox * box, m_boxes)
{
if(box == editedBox)
{
continue;
}
if(currentText != "")
{
// remove the current text from the other boxes
int index = box->findText(currentText);
if(index != -1)
{
box->removeItem(index);
}
}
if(m_previousText[editedBox] != "")
{
// add the previous text back into the lists for the other boxes
box->addItem(m_previousText[editedBox]);
qDebug() << "Adding back" << m_previousText[editedBox];
}
}
m_previousText[editedBox] = currentText;
}
Note that when an item is added back into a box's list, it just gets tacked onto the end of the list, so over time the order of your items may get scrambled.
Hope that helps.

Resources