Qt. Redefine QString::compare in heavy applications - qt

My task is custom sorting items in QStandardItemModel.
By default for a sequance of rows
text1
text11
text12
text100
text110
text120
text1110
function QStandardItemModel::sort() sorting it as
text1
text100
text11
text110
text1110
text12
text120
I want that would be
text1
text11
text12
text100
text110
text120
text1110
For this purpose I overload function int QString::compare(const QString &s) const in the separeted compare.cpp file.
int QString::compare(const QString &s) const
{
QString strL = "";
strL.append(this);
QString strR = "";
strR.append(s);
QStringList list = strL.split(QRegExp("\\D+"),QString::SkipEmptyParts);
foreach (QString num, list) {
strL.replace(num, QString("%1").arg(num,10,'0'));
}
list = strR.split(QRegExp("\\D+"),QString::SkipEmptyParts);
foreach (QString num, list) {
strR.replace(num, QString("%1").arg(num,10,'0'));
}
return strL.localeAwareCompare(strR);
}
that using in operator
virtual bool operator< ( const QStandardItem & other ) const.
Such function as compare can be redefined in the separate file and it is simple to add it in *.pro and easy application will find its realization. But with more difficult applications such way it is impossible. Please tell me Why?
Example : code

Rather than using a QStandardItemModel directly, you want to wrap it in a QSortFilterProxyModel. This class was designed for exactly the situation you describe--when you want to implement custom sorting or filtering behavior. Just implement the QSortFilterProxyModel::lessThan method to reflect the desired behavior.

QStandardItemModel has a virtual function sort(int column, Qt::SortOrder order = Qt::AscendingOrder). I think it will be easier to subclass QStandardItemModel and reimplement sortfunction.

I did!
When i said "heavy application", i means application, that contains and binds many other plugins and libs. And for this purpose what I create the new lib with name QStringCompare, that contains one file compare.cpp with my new definiotoin of compare:
#include <QStringList>
#include <QRegExp>
int Q_DECL_EXPORT QString::compare(const QString &s) const
{
QString strL = "";
strL.append(this);
QString strR = "";
strR.append(s);
QStringList list = strL.split(QRegExp("\\D+"),QString::SkipEmptyParts);
foreach (QString num, list) {
strL.replace(num, QString("%1").arg(num,10,'0'));
}
list = strR.split(QRegExp("\\D+"),QString::SkipEmptyParts);
foreach (QString num, list) {
strR.replace(num, QString("%1").arg(num,10,'0'));
}
return strL.localeAwareCompare(strR);
}
and it links QStringCompare.lib to *.pro of Main apllication of my project. Generally it's not necessary to declare it in *.h files. All other plug-ins inherit this redefinition. The experiments showed that it is necessary to links to main application.
As that so.
There can be I am mistaken in reasonings, but it's working on linux and windows.
This is source of QStringCompare.libs. You can try.

Related

Add String from textEdit to a QStack

I am trying to capture the contents from textEdit and add it to a QStack. The content I am splitting so to be able to reverse the order of the sentence captured. I already have that part covered, but I want to be able to convert from QStringList to be pushed to the QStack. This is what I have:
void notepad::on_actionReversed_Text_triggered()
{
QString unreversed = ui->textEdit->toPlainText();
QStringList ready = unreversed.split(QRegExp("(\\s|\\n|\\r)+"), QString::SkipEmptyParts);
QStack<QString> stack;
stack.push(ready);
QString result;
while (!stack.isEmpty())
{
result += stack.pop();
ui->textEdit->setText(result);
}
}
QStack::push only takes objects of it's template type.
i.e. In your case you must push QString's onto the QStack<QString>, and not a list.
So, iterate the list of strings pushing each one in turn.
foreach (const QString &str, ready) {
stack.push(str);
}
Something else that is wrong is that you are updating textEdit inside the for loop. You actually want to build up the string in the loop and afterwards update the text.
QString result;
while (!stack.isEmpty()) {
result += stack.pop();
}
ui->textEdit->setText(result);
An alternate answer could be to do away with the stack and just iterate the QStringList ready in reverse order to build up result string.

QStringList split() function and simplifyWhiteSpace() function

I am using Qt5 and errors exist from this line of codes after running sample project I found on the internet.
QFile f( "world.txt" );
if( f.open( QIODevice::ReadOnly ) ) {
QTextStream ts( &f );
Vertex v[3];
int vcount = 0;
bool allok, ok;
while( !ts.atEnd() )
{
QStringList line = QString::split( " ",ts.readLine().simplifyWhiteSpace() );
Errors are:
split is not a member of QStringList
simplifyWhiteSpace is not a member of QString
I don't know how to convert the line to work on Qt5.
Both QStringList::split() and QString::simplifyWhitespace() were functions in Qt3, and have been renamed or moved for Qt5 (which you are using according to your tags).
For QStringList::split(), the documentation says:
Use QString::split(sep, QString::SkipEmptyParts) or QString::split(sep, QString::KeepEmptyParts) instead.
Be aware that the QString::split()'s return value is a QStringList that always contains at least one element, even if str is empty.
You already changed this in your edit, so you are left with QString::simplifyWhitespace(), where the documentation says:
QString QString::simplifyWhiteSpace () const
Use simplified() instead.

Config file gets overwritten in qt

I am writing data to a config file using the following code.
QSettings settings("/root/configFile.ini",QSettings::IniFormat);
QString userName = lineEditUsername.text();
QString password = lineEditPassword.text();
QList<QString> listUsername;
QList<QString> listPassword;
settings.beginWriteArray("UserData");
for(i=0;i<listUsername.size();i++)
{
Qstring user = listUsername.at(i);
Qstring pass = listPassword.at(i);
settings.setArryIndex(i);
settings.setValue("Username",user);
settings.setValue("Password",pass);
}
settings.endArray();
}
Now when I run the code first time and give 4 or 5 values they are formed in proper order in the file. However if I run the application for second time the values start overwriting from first position. Can some one suggest me some solution for this?
Instead of creating and maintaining arrays and indexes, I would propose to create user credentials map and store it in the settings file as follows:
QSettings settings("/root/configFile.ini", QSettings::IniFormat);
QString userName = lineEditUsername.text();
QString password = lineEditPassword.text();
QList<QString> listUsername;
QList<QString> listPassword;
//settings.beginWriteArray("UserData");
QVariantMap userDataMapping;
for(int i = 0; i < listUsername.size() ; i++)
{
QString user = listUsername.at(i);
QString pass = listPassword.at(i);
userDataMapping[user] = pass;
//settings.setArryIndex(i);
//settings.setValue("Username",user);
//settings.setValue("Password",pass);
}
// Store the mapping.
settings.setValue("UserData", userDataMapping);
//settings.endArray();
// ...
This will store your data in ini file in the following format:
UserData=#Variant(\0\0\0\b\0\0\0\x1\0\0\0\x6\0\x64\0\x64\0\x64\0\0\0\n\0\0\0\x6\0\x62\0\x62\0\x62)
When you read settings, do something like this:
[..]
QVariant v = settings.value("UserData");
QVariantMap map = v.value<QVariantMap>();
QMapIterator<QString, QVariant> i(map);
while (i.hasNext()) {
i.next();
QString user = i.key();
QString pass = i.value().toString();
}
You need to retrieve the amount of existing entries before adding a new one. Something like this:
int size = settings.beginReadArray( "UserData" );
settings.endArray();
settings.beginWriteArray( "UserData" );
settings.setArrayIndex( size ); // Note: Maybe 'size - 1', not sure
// ...
settings.endArray();
setArrayIndex( size ) will move the array index to the end and will thus no longer override an existing entry

foreach not working on list of QPair

Using Qt, I want this code to work:
QList<QPair<QString, QString>> list;
foreach (QPair<QString, QString> pair, list)
{
}
instead, I get the error:
'pair' : undeclared identifier
Using a typedef I can make it work, but this is not what I want (unless this is the only thing that works):
typedef QPair<QString, QString> MyPair;
QList<MyPair> list;
foreach (MyPair pair, list)
{
}
Can anyone explain why the first foreach doesn't compile?
it's not the foreach error. It's declaration error. You declared list like this:
QList<QPair<QString, QString>> list;
while it should this way:
QList<QPair<QString, QString> > list;
Just declare QPair outside of loop:
QPair<QString,QString> pair;
foreach(pair,list){
}
It is not possible to use template classes inside qt foreach statement which contains more than one template parameter, because comma separator conflicts with comma separator inside macros.
#define add( a, b ) (a + b)
template < typename T1, typename T2 >
struct DATA
{
static const T1 val1 = 1;
static const T2 val2 = 2;
};
// Usage
const int c = add( 1, 2 ); // OK
const int d = add( DATA< int, int >::val1 , DATA< int, int >::val2 ); // FAIL
because macros add will interpret "DATA< int" as first argument, and " int >::val1" as second, and so on.
Some explanation with above answer... if your compiler accept
QList<QPair<QString, QString>> list;
giving no error on such declaration, reasons for topic caster error is different and indeed has to do with a fact that declaration must be done outside of foreach() loop. That's explained in QT documentation.
regarding >> and > >... that's old story and latest GCC (so linux/mac) consider it to be a syntax mistake, because it's not conforming standard. >> in GCC manner is treated as operator with all follow-up errors..

How can I get the selected VALUE out of a QCombobox?

In Qt, I can get the selected text of a QComboBox by using the
combobox->currentText() method.
How can I get the selected value?
I searched for help but I couldn't find a method currentData() which I expected to find. I could only find combobox->currentIndex()
Is there a smarter way to do it other than combobox->itemData(combobox->currentIndex())?
Update: This is no longer necessary as of Qt 5. A currentData() method has been added http://doc.qt.io/qt-5/qcombobox.html#currentData-prop
It seems you need to do combobox->itemData(combobox->currentIndex()) if you want to get the current data of the QComboBox.
If you are using your own class derived from QComboBox, you can add a currentData() function.
This one can get the text of current index:
QString cb = cbChoice ->currentText();
you can set QVariant data for all items, then you can get the value when you need it.
there is an example code for this situation:
ui.comboBoxSheetSize->addItem("128 m", QVariant(128));
ui.comboBoxSheetSize->addItem("256 m", QVariant(256));
ui.comboBoxSheetSize->addItem("512 m", QVariant(512));
ui.comboBoxSheetSize->addItem("1024 m", QVariant(1024));
...
void Page::onComboSheetSizeChanged( int index )
{
int value = ui.comboBoxSheetSize->itemData(index).toInt();
}
by the way, i think i misunderstood your question. i think the way you get data is smart enough?
The member function QComboBox::currentData has been added since this question was asked, see this commit
I had same issue
I have solved by
value = self.comboBox.currentText()
print value
This is my OK code in QT 4.7:
//add combobox list
QString val;
ui->startPage->clear();
val = "http://www.work4blue.com";
ui->startPage->addItem(tr("Navigation page"),QVariant::fromValue(val));
val = "https://www.google.com";
ui->startPage->addItem("www.google.com",QVariant::fromValue(val));
val = "www.twitter.com";
ui->startPage->addItem("www.twitter.com",QVariant::fromValue(val));
val = "https://www.youtube.com";
ui->startPage->addItem("www.youtube.com",QVariant::fromValue(val));
// get current value
qDebug() << "current value"<<
ui->startPage->itemData(ui->startPage->currentIndex()).toString();
I'm astonished that there isn't an activated signal and have the same problem. I solved it by making a subclass of QComboBox. I think it's better to avoid having to directly access the object and call its functions because that means more tight coupling and goes against Qt's philosophy. So here's the class I made that works for me.
class SmartComboBox : public QComboBox {
Q_OBJECT
private slots:
void triggerVariantActivated(int index);
public:
SmartComboBox(QWidget *parent);
signals:
void activated(const QVariant &);
};
And the implementation
void SmartComboBox::triggerVariantActivated(int index)
{
activated(itemData(index));
}
SmartComboBox::SmartComboBox(QWidget *parent)
:QComboBox(parent)
{
connect(this, SIGNAL(activated(int)), this, SLOT(triggerVariantActivated(int)));
}
The question is old, but maybe, somebody need an actual answer.
In the QGIS 3.4 you can get the value from the QComboBox with the method currentData().
Example: comboBox.currentData()
Link: https://doc.qt.io/qt-5/qcombobox.html#currentData-prop
I did this
QDir path("/home/user/");
QStringList _dirs = path.entryList(QDir::Dirs);
std::cout << "_dirs_count = " << _dirs.count() << std::endl;
ui->cmbbox->addItem(Files);
ui->cmbbox->show();
You will see with this that the QStringList named _dirs is structured like an array whose members you can access via an index up to the value returned by _dirs.count()
I had the issue and
QString str = m_UI->myComboBox->currentText();
solved this.
if you are developing QGIS plugins then simply
self.dlg.cbo_load_net.currentIndex()
I know I'm very late but for those who still have that problem, it can be solved easily.
I use Qt 5.3 and it works fine. No need to create a function or all that.
int valueComboBox;
valueComboBox = comboBox->currentIndex();
and it works !
Hope it helps !
I confirm the easiest way is to do this:
uiAnalyseAssets::AnalyseAssets(QWidget *parent)
: QWidget(parent)
{
ui.comboBox->addItem("text1");
ui.comboBox->addItem("text2");
...
}
void mainFunction::yourFunction( int index )
{
int value = ui.comboBox->currentText();
}

Resources