Why QCompleter works differently with delegates? - qt

I am trying to implement auto-completion for QLineEdit.
Here see my code:
#ifndef COMPLETER_H
#define COMPLETER_H
#include <QCompleter>
#include <QString>
#include <QStringList>
#include <QLineEdit>
class Completer:public QCompleter
{
Q_OBJECT
public:
explicit Completer(QStringList stringList, QObject *parent=0);
virtual QString pathFromIndex(const QModelIndex &index)const;
virtual QStringList splitPath(const QString&)const;
public slots:
void onLineEditTextChanged() const;
private:
mutable int cursorPos_;
};
class ExpressionLineEdit: public QLineEdit
{
Q_OBJECT
public:
explicit ExpressionLineEdit(QWidget *parent=0);
private:
QStringList stringList;
Completer *completer_;
};
#endif // COMPLETER_H
#include <completer.h>
#include <QDebug>
Completer::Completer(QStringList stringList, QObject *parent)
: QCompleter(stringList,parent)
, cursorPos_(-1)
{
}
ExpressionLineEdit::ExpressionLineEdit(QWidget* parent)
: QLineEdit(parent)
{
stringList << "minRoute" << "minPitch" << "minSpacing";
completer_ = new Completer(stringList, this);
setCompleter(completer_);
QObject::connect(this, SIGNAL(textChanged(const QString&)),
completer_, SLOT(onLineEditTextChanged()));
QObject::connect(this, SIGNAL(cursorPositionChanged(int, int)),
completer_, SLOT(onLineEditTextChanged()));
}
QString Completer::pathFromIndex(const QModelIndex &index) const
{
QString newStr = index.data(Qt::EditRole).toString();
ExpressionLineEdit *lineEdit = qobject_cast<ExpressionLineEdit*>(parent());
QString str = lineEdit->text();
int prevSpacePos = str.mid(0, lineEdit->cursorPosition()).lastIndexOf(' ');
int curPos = lineEdit->cursorPosition();
int nextSpacePos = str.indexOf(' ', curPos);
if (nextSpacePos == -1) {
nextSpacePos = str.size();
}
QString part1 = str.mid(0, prevSpacePos + 1);
QString pre = str.mid(prevSpacePos + 1, curPos - prevSpacePos - 1);
QString post = str.mid(curPos, nextSpacePos - curPos);
QString part2 = str.mid(nextSpacePos);
onLineEditTextChanged();
cursorPos_ = curPos + newStr.size() - pre.size();
return part1 + newStr + part2;
}
void Completer::onLineEditTextChanged() const
{
qDebug() << "Completer::onLineEditTextChanged()" << cursorPos_;
if (cursorPos_ != -1) {
ExpressionLineEdit *lineEdit = qobject_cast<ExpressionLineEdit*>(parent());
lineEdit->setCursorPosition(cursorPos_);
cursorPos_ = -1;
}
}
QStringList Completer::splitPath(const QString &path) const
{
cursorPos_ = -1;
ExpressionLineEdit *lineEdit = qobject_cast<ExpressionLineEdit*>(parent());
QString text = lineEdit->text();
QStringList stringList;
QString str;
int index = text.mid(0,lineEdit->cursorPosition()).lastIndexOf(' ');
str = text.mid(index, lineEdit->cursorPosition()-index);
str.trimmed();
str.replace(" ", "");
stringList << str;
onLineEditTextChanged();
return stringList;
}
#include <completer.h>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ExpressionLineEdit le;
le.show();
return a.exec();
}
For this code ExpressionLineEdit and Completer work properly (as expected).
But when I try to set the to QTreeView and QSyledItemDelegate, the the behavior is changed.
I tried to reimplement the eventFilter function of QSyledItemDelegate, but it does not word.
I tried to set ExpressionLineEdit to other QWidget and set the QWidget to QTreeView (for QSyledItemDelegate not to work with ExpressionLineEdit directly), but again it did not help.
Here is the code with QTreeView and QSyledItemDelegate.
#include <QTreeView>
#include <QVBoxLayout>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <Completer.h>
class QEvent;
class Delegate:public QStyledItemDelegate
{
public:
Delegate(QObject* parent = 0)
:QStyledItemDelegate(parent){}
bool eventFilter(QObject* editor,QEvent* event){return false;}
virtual bool editorEvent ( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex& index){return false;}
QWidget* createEditor(QWidget* parent,const QStyleOptionViewItem &option,const QModelindex &index) const
{
if(index.column() != 1) return 0;
QWidget* w = new QWidget(parent);
ExpressionLineEdit *le = new ExpressionLineEdit(w);
QVBoxLayout* lay = new QVBoxLayout(w);
lay->setContentsMargins(0, 0, 0, 0);
lay->addWidget(le);
w->setLayout(lay);
return w;
}
};
class Tree:public QTreeView
{
public:
Tree(QWidget* parent = 0)
:QTreeView(parent)
{
QStandardItemModel *model = new QStandardItemModel(this);
model->setRowCount(1);
model->setColumnCount(2);
QStandardItem *item = new QStandardItem("Item");
model->setItem(0,0,item);
setModel(model);
Delegate *d = new Delegate(this);
setItemDelegate(d);
}
void keyPressEvent ( QKeyEvent * event ){}
};
#include <QApplication>
#include <Completer.h>
#include <Tree.h>
int main(int argc, char ** argv)
{
QApplication app(argc,argv);
Tree t;
t.show();
return app.exec();
}
Please help to understand why same code works differently for this 2 cases.
Please help to fix the behavior of Completer.

Related

Accessing a delegate's input value from the model

I'm using a custom QTableView with a custom QAbstractTableModel and a QItemDelegate. I'd need to access the contents of the delegate's editor while the user is editing it, and after several attempts, I couldn't find anything satisfying.
Indeed, I've tried several things.
First: trying to access the delegate's current input (created through createEditor) through a property defined in QItemDelegate but... it seems that none exists. That's why I tried to add a QWidget* editor property and setting it in the createEditor.
Unfortunately, QItemDelegate's createEditor is supposed to be const, which makes me unable to set my property there (and since I don't control what calls createEditor, I can't do it before or after).
I don't really know what to do here. Actually, I also needed to know when the user started (or stopped) editing the cell content, which I eventually achieved by creating two const signals (editingStarted and editingStopped). I could probably create a const editorOpened(QWidget*) signal but it just feels bad and ugly...
I can't believe nothing "official" exists to achieve what I'm trying to do, hence this question. If I have everything wrong from the beginning, I'd be glad to know. If you have any other ideas, please suggest.
EDIT: Here is a minimal working example
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include <QTableView>
#include "mytableview.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
auto tableView = new MyTableView(this);
setCentralWidget(tableView);
}
MainWindow::~MainWindow()
{
}
MyItemDelegate.h
#ifndef MYITEMDELEGATE_H
#define MYITEMDELEGATE_H
#include <QItemDelegate>
#include <QLineEdit>
#include <QStandardItemModel>
class MyItemDelegate : public QItemDelegate
{
Q_OBJECT
public:
MyItemDelegate(QObject* parent);
virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
virtual void onCloseEditor();
virtual ~MyItemDelegate() = default;
signals:
// Const signals trick
void editingStarted() const;
void editingFinished() const;
void editorOpened(const QWidget*) const;
};
#endif // MYITEMDELEGATE_H
MyItemDelegate.cpp
#include "myitemdelegate.h"
MyItemDelegate::MyItemDelegate(QObject* parent) : QItemDelegate(parent)
{
connect(this, &QItemDelegate::closeEditor, this, &MyItemDelegate::onCloseEditor);
}
QWidget* MyItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
auto lineEdit = new QLineEdit(parent);
emit editingStarted();
emit editorOpened(lineEdit);
return lineEdit;
}
void MyItemDelegate::onCloseEditor()
{
emit editingFinished();
}
MyTableView.h
#ifndef MYTABLEVIEW_H
#define MYTABLEVIEW_H
#include <QTableView>
#include <QDebug>
#include "myitemdelegate.h"
class MyTableView : public QTableView
{
Q_OBJECT
public:
explicit MyTableView(QWidget *parent = nullptr);
signals:
public slots:
};
#endif // MYTABLEVIEW_H
MyTableView.cpp
#include "mytableview.h"
MyTableView::MyTableView(QWidget *parent) : QTableView(parent)
{
MyItemDelegate* delegate = new MyItemDelegate(this);
QStandardItemModel* model = new QStandardItemModel(this);
setItemDelegate(delegate);
setModel(model);
QList<QList<QStandardItem*>> items;
for(int i = 0; i < 10; i++)
{
items << QList<QStandardItem*>();
for (int j = 'A'; j < 'E'; j++)
items[i] << new QStandardItem(QString("%1,%2").arg(i).arg(static_cast<char>(j)));
}
for (const auto& row : items)
model->appendRow(row);
connect(delegate, &MyItemDelegate::editingStarted, []() {
qDebug() << "Editing started";
});
connect(delegate, &MyItemDelegate::editingFinished, []() {
qDebug() << "Editing finished";
});
connect(delegate, &MyItemDelegate::editorOpened, [](const QWidget* editor) {
auto lineEdit = qobject_cast<const QLineEdit*>(editor);
connect(lineEdit, &QLineEdit::textChanged, [](const QString& text) {
qDebug() << text;
});
});
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
The following solution maybe fits your needs. I just defined a new signal inside the delegate and connected to it inside the class owning the delegate.
MyItemDelegate.h
#ifndef MYITEMDELEGATE_H
#define MYITEMDELEGATE_H
#include <QStyledItemDelegate>
class MyItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
MyItemDelegate(QObject* parent);
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
virtual ~MyItemDelegate() = default;
signals:
void valueChanged(const QString&);
};
#endif // MYITEMDELEGATE_H
MyItemDelegate.cpp
#include "myitemdelegate.h"
#include <QLineEdit>
MyItemDelegate::MyItemDelegate(QObject* parent) : QStyledItemDelegate(parent)
{
}
QWidget* MyItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
auto lineEdit = new QLineEdit(parent);
connect(lineEdit, &QLineEdit::textChanged, this, &MyItemDelegate::valueChanged);
return lineEdit;
}
MyTableView.cpp
#include "mytableview.h"
#include <QStandardItemModel>
MyTableView::MyTableView(QWidget *parent) : QTableView(parent)
{
MyItemDelegate* delegate = new MyItemDelegate(this);
QStandardItemModel* model = new QStandardItemModel(this);
setItemDelegate(delegate);
setModel(model);
QList<QList<QStandardItem*>> items;
for(int i = 0; i < 10; i++)
{
items << QList<QStandardItem*>();
for (int j = 'A'; j < 'E'; j++)
items[i] << new QStandardItem(QString("%1,%2").arg(i).arg(static_cast<char>(j)));
}
for (const auto& row : items)
model->appendRow(row);
connect(delegate, &MyItemDelegate::valueChanged, [](auto v) { qDebug() << v; });
}

QWebEngine download restart after a reboot

I did an application to download softwares. It's works well with QWebengine.
For the second version, I need to implement the restart of the download after the application is turned off.
My goal is to get possible to restart the same download at the same status after a reboot.
Is it possible?
How to save the status of the current download in a file with WebEngineDownloadItem ?
Thank you for your help
This is how I did :
DownloaderWidget.hpp
#ifndef DOWNLOADERWIDGET_HPP
#define DOWNLOADERWIDGET_HPP
# include <QUrl>
# include <QApplication>
# include <QPushButton>
# include <QString>
# include <QWidget>
# include <QLabel>
# include <QVBoxLayout>
# include <QProgressBar>
# include "downloadermanager.hpp"
class DownloaderWidget : public QWidget
{
Q_OBJECT
public:
explicit DownloaderWidget(QWidget *parent = nullptr);
signals:
public slots:
void download(void);
void pause(void);
void resume(void);
private slots:
void progress(int percent);
private:
static QString const
URL;
QLabel *m_url;
QPushButton *m_start;
QPushButton *m_resume;
QPushButton *m_pause;
QProgressBar *m_status;
DownloaderManager *m_download_manager;
};
#endif // DOWNLOADERWIDGET_HPP
DownloaderManager.hpp
#ifndef DOWNLOADERMANAGER_HPP
#define DOWNLOADERMANAGER_HPP
# include <QUrl>
# include <QObject>
# include <QDebug>
# include <QNetworkAccessManager>
# include <QNetworkRequest>
# include <QNetworkReply>
# include <QFile>
# include <QByteArray>
# include <QStandardPaths>
class DownloaderManager : public QObject
{
Q_OBJECT
public:
explicit DownloaderManager(QObject *parent = nullptr);
signals:
void downloadComplete(void);
void progress(int const percentage);
public slots:
void download(QUrl const &url);
void pause();
void resume();
private slots:
void download(QNetworkRequest &request);
void finished();
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void error(QNetworkReply::NetworkError code);
private:
QNetworkAccessManager
*m_manager;
QNetworkRequest m_request;
QNetworkReply *m_reply;
QFile *m_file;
qint64 m_downloadSizeAtPause;
QString m_name;
QString get_file_name(QUrl const &url);
};
#endif // DOWNLOADERMANAGER_HPP
DownloaderWidget.cpp
#include "downloaderwidget.hpp"
QString const DownloaderWidget::URL = "My great URL";
DownloaderWidget::DownloaderWidget(QWidget *parent)
: QWidget(parent),
m_url(new QLabel(URL, this)),
m_start(new QPushButton("Start", this)),
m_resume(new QPushButton("Resume", this)),
m_pause(new QPushButton("Pause", this)),
m_status(new QProgressBar(this)),
m_download_manager(new DownloaderManager(this))
{
QVBoxLayout *main_layout = new QVBoxLayout(this);
m_status->setOrientation(Qt::Horizontal);
main_layout->addWidget(m_url);
main_layout->addWidget(m_status);
main_layout->addWidget(m_start);
main_layout->addWidget(m_pause);
main_layout->addWidget(m_resume);
QObject::connect(m_start, SIGNAL(clicked()), this, SLOT(download()));
QObject::connect(m_pause, SIGNAL(clicked()), this, SLOT(pause()));
QObject::connect(m_resume, SIGNAL(clicked()), this, SLOT(resume()));
QObject::connect(m_download_manager, SIGNAL(downloadComplete()), qApp, SLOT(quit()));
QObject::connect(m_download_manager, SIGNAL(progress(int)), this, SLOT(progress(int)));
this->m_pause->setEnabled(false);
this->m_resume->setEnabled(false);
}
void DownloaderWidget::download(void)
{
this->m_download_manager->download(QUrl(URL));
this->m_start->setEnabled(false);
this->m_pause->setEnabled(true);
}
void DownloaderWidget::pause()
{
this->m_download_manager->pause();
this->m_pause->setEnabled(false);
this->m_resume->setEnabled(true);
}
void DownloaderWidget::resume(void)
{
this->m_download_manager->resume();
this->m_pause->setEnabled(true);
this->m_resume->setEnabled(false);
}
void DownloaderWidget::progress(int percent)
{
this->m_status->setValue(percent);
}
DownloaderManager.cpp
#include "downloadermanager.hpp"
DownloaderManager::DownloaderManager(QObject *parent) :
QObject(parent),
m_manager(new QNetworkAccessManager(this)),
m_request(),
m_reply(nullptr),
m_file(nullptr),
m_downloadSizeAtPause(0),
m_name("")
{
}
QString DownloaderManager::get_file_name(QUrl const &url)
{
QStringList list = url.toString().split("/");
this->m_name = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + "/" + list[list.length() - 1];
return (this->m_name + ".download");
}
void DownloaderManager::download(QUrl const &url)
{
this->m_name = this->get_file_name(url);
qDebug() << "Download : file = " << this->m_name;
this->m_downloadSizeAtPause = 0;
this->m_request = QNetworkRequest(url);
this->m_file = new QFile(this->m_name);
this->m_file->open(QIODevice::ReadWrite | QIODevice::Append);
if (this->m_file->size() != 0)
this->resume();
else
this->download(this->m_request);
}
void DownloaderManager::pause(void)
{
qDebug() << "pause()";
if(this->m_reply == nullptr)
return;
QObject::disconnect(this->m_reply, SIGNAL(finished()), this, SLOT(finished()));
QObject::disconnect(this->m_reply, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(downloadProgress(qint64, qint64)));
QObject::disconnect(this->m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
this->m_reply->abort();
this->m_file->write(this->m_reply->readAll());
this->m_reply = nullptr;
}
void DownloaderManager::resume(void)
{
qDebug() << "resume()";
this->m_file->flush();
this->m_downloadSizeAtPause = this->m_file->size();
QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(this->m_downloadSizeAtPause) + "-";
this->m_request.setRawHeader("Range",rangeHeaderValue);
this->download(this->m_request);
}
void DownloaderManager::download(QNetworkRequest &request)
{
qDebug() << "download( QNetworkRequest& request )";
this->m_reply = this->m_manager->get(request);
QObject::connect(this->m_reply, SIGNAL(finished()), this, SLOT(finished()));
QObject::connect(this->m_reply, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(downloadProgress(qint64, qint64)));
QObject::connect(this->m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
}
void DownloaderManager::finished(void)
{
qDebug() << "finihsed";
this->m_file->rename(this->m_name + ".download", this->m_name);
this->m_file->close();
this->m_file = nullptr;
this->m_reply = nullptr;
emit downloadComplete();
}
void DownloaderManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
qDebug() << "Download Progress: Received=" << this->m_downloadSizeAtPause + bytesReceived <<": Total=" << this->m_downloadSizeAtPause + bytesTotal;
this->m_file->write(this->m_reply->readAll());
int percentage =
static_cast<int>((this->m_downloadSizeAtPause + bytesReceived) * 100 ) / (this->m_downloadSizeAtPause + bytesTotal);
qDebug() << percentage;
emit progress(percentage);
}
void DownloaderManager::error(QNetworkReply::NetworkError code)
{
qDebug() << "Error:" <<code;
}
main.cpp
#include <QApplication>
#include "downloaderwidget.hpp"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
DownloaderWidget downloader;
downloader.show();
return (app.exec());
}
I hope this piece of code will help some one in the same case than me Thank you

qt gnuplot instance set xrange with variables

I basically just started using Gnuplot and in trying to set xrange/yrange I am not able to find out how to set variable bounds.
For example : instance << "set yrange [-10:10]" works perfectly
but instance << "set yrange [yrange1:yrange2] doesn't.
yrange1, yrange2 are variables in which user input is stored. That way the user can decide the bounds for gnuplot
Is there a simple way to do this?
Edit : Sorry.Here is the code
qtgnuplotlib-example.cpp
//#include <QApplication>
#include "visualization.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
Visualization v;
v.show();
return app.exec();
}
visualization.h
#ifndef VISUALIZATION_H
#define VISUALIZATION_H
#include <QMainWindow>
#include <QtGnuplot/QtGnuplotWidget.h>
#include <QtGnuplot/QtGnuplotInstance.h>
namespace Ui {
class Visualization;
}
class Visualization : public QMainWindow
{
Q_OBJECT
public:
explicit Visualization(QWidget *parent = 0);
~Visualization();
private:
QtGnuplotWidget *widget;
QtGnuplotInstance *instance;
protected:
bool eventFilter(QObject *obj, QEvent *event);
private slots:
void on_actionExit_triggered();
void on_actionOpen_triggered();
void on_pushButton_clicked();
private:
Ui::Visualization *ui;
};
#endif // VISUALIZATION_H
visualization.cpp
#include <QFileDialog>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
#include <QString>
#include "visualization.h"
#include "ui_visualization.h"
using namespace std;
Visualization::Visualization(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Visualization)
{
ui->setupUi(this);
widget = new QtGnuplotWidget();
widget->installEventFilter(this);
widget->setStatusLabelActive(true);
instance = new QtGnuplotInstance();
instance->setWidget(widget);
}
Visualization::~Visualization()
{
delete ui;
delete instance;
delete widget;
}
void Visualization::on_actionExit_triggered()
{
qApp->quit();
}
void Visualization::on_actionOpen_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QString(),
tr("All Files (*.*)"));
if (!fileName.isEmpty()) {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
return;
}
QTextStream in(&file);
QString str = in.readAll();
ui->equationsTxt->setText(str);
file.close();
}
}
bool Visualization::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress)
{
if (obj == this->widget) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent->button() == Qt::LeftButton) {
ui->outputTxt->setText( this->widget->getStatusLabel()->text());
}
}
}
return QObject::eventFilter(obj, event);
}
void Visualization::on_pushButton_clicked()
{
widget->show();
widget->resize(QSize(800,600));
int yrange1 = 5;
int yrange2 = 10;
// *instance <<\
//"set yrange [-1.5:1.5]\nset xrange [-1.5:1.5]\nset isosamples 500,500\nf(x,y)= x**2+y**2-1\nset contour\nset cntrparam levels discrete 0\nset view 0,0\nunset ztics\nunset surface\nsplot f(x,y)\n";
//here is where I am stuck
*instance << "set tics scale 0.75\nset xtics 1\nset ytics 1\nset yrange [-10:10]\nset xlabel 'x'\nset ylabel 'y'\nset zeroaxis\nplot \"<echo '1 2'\" notitle\n";
}
The QtGnuplotInstance class provides an exec method which you can pass a QByteArray with commands:
QtGnuplotInstance instance = new QtGnuplotInstance();
QString command;
QTextStream(&command) << "set yrange [" << yrange1 << ":" << yrange2 << "]";
instance.exec(command.toLocal8Bit());
I cannot test this at the moment, but the direction should be correct.

QStandardItem converts unsigned int to int after editing

I create a QTableview with a QStandardItemModel, after editing the QStandardItem
the type changed from unsigned int to int.
This behavior just happen to unsigned int and just while the user is editing it, other datatypes stay.
window.cpp
#include "window.h"
#include "ui_window.h"
#include <QTableView>
#include <QStandardItem>
#include <QDebug>
Window::Window(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Window)
{
ui->setupUi(this);
QTableView *tblview = new QTableView(this);
model = new QStandardItemModel(0,0);
tblview->setModel(model);
QStandardItem *data=new QStandardItem;
data->setEditable(true);
data->setData(QVariant((uint)1), Qt::DisplayRole);
model->setItem(0, 0, data);
tblview->show();
QModelIndex index = model->index( 0, 0, QModelIndex() );
tblview->setGeometry(0,0,200,200);
//result QVariant(uint, 1)
qDebug() << model->data(index);
connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(dataChanged(QStandardItem*)));
}
Window::~Window()
{
delete ui;
}
void Window::dataChanged(QStandardItem* stditem)
{
//result
//QVariant(int, 3)
//expected result
//QVariant(uint, 3)
qDebug() << model->data(stditem->index());
}
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QMainWindow>
#include <QStandardItem>
namespace Ui {
class Window;
}
class Window : public QMainWindow
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
~Window();
private:
Ui::Window *ui;
QStandardItemModel* model;
private slots:
void dataChanged(QStandardItem*);
};
#endif // WINDOW_H
The second qDebug() does not print nothing because you do not define the role. This will work:
qDebug() << stditem->data(Qt::DisplayRole);
Now concerning the conversion from an uint QVariant to an int after the edit. This is natural and can be explained as follows:
First you have a QVariant that is uint
QVariant v = QVariant((uint) 5)); // It is uint now...
After the edit, the model changes its value with the int value that is entered
v = QVariant(10); // Now v is not uint anymore but int
In order to avoid it you should subclass the QStandardItemModel, and reimplement the setData function. There you should explicitly cast the new value to uint.

Setting focus on QLineEdit while showing the QListView view

In Qt, there is a QCompleter class which provides auto-complete funtionanity.
I want to use QListView to finish the same thing. In the following code, When the QListView shows, QLineEdit will lose focus. How could I keep QLineEdit's focus?
1) mdict.h:
#include <QtGui/QWidget>
class QLineEdit;
class QListView;
class QModelIndex;
class mdict : public QWidget
{
Q_OBJECT
public:
mdict(QWidget *parent = 0);
~mdict() {}
private slots:
void on_textChanged(const QString &);
void completeText(const QModelIndex &);
private:
QLineEdit *mLineEdit;
QListView *mView;
};
2) mdict.cpp
#include <cassert>
#include <QtGui>
#include "mdict.h"
mdict::mdict(QWidget *parent) : QWidget(parent), mLineEdit(0), mView(0)
{
mLineEdit = new QLineEdit(this);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(mLineEdit);
layout->addStretch(100);
setLayout(layout);
QStringList stringList;
stringList << "m0" << "m1" << "m2";
QStringListModel *model = new QStringListModel(stringList);
mView = new QListView(this);
mView->setModel(model);
mView->setEditTriggers(QAbstractItemView::NoEditTriggers);
mView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mView->setSelectionBehavior(QAbstractItemView::SelectRows);
mView->setSelectionMode(QAbstractItemView::SingleSelection);
mView->setParent(0, Qt::Popup);
mView->setFocusPolicy(Qt::NoFocus);
mView->setFocusProxy(mLineEdit);
connect(mLineEdit, SIGNAL(textChanged(const QString&)),
this, SLOT(on_textChanged(const QString &)));
connect(mView, SIGNAL(activated(const QModelIndex &)),
this, SLOT(completeText(const QModelIndex &)));
connect(mView, SIGNAL(clicked(const QModelIndex &)),
this, SLOT(completeText(const QModelIndex &)));
}
void mdict::on_textChanged(const QString &text)
{
int lineEidtWidth = mLineEdit->width();
mView->setMinimumWidth(lineEidtWidth);
mView->setMaximumWidth(lineEidtWidth);
mView->setMaximumHeight(60);
QPoint p(0, mLineEdit->height());
int x = mLineEdit->mapToGlobal(p).x();
int y = mLineEdit->mapToGlobal(p).y();
mView->move(x, y);
mView->show();
}
void mdict::completeText(const QModelIndex &index)
{
mLineEdit->setText(index.data().toString());
mView->hide();
}
3) main.cpp
#include "mdict.h"
#include <QtGui>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
mdict w;
w.show();
return a.exec();
}
Use Qt::ToolTip instead of Qt::Popup, in this way:
mView->setParent(0, Qt::ToolTip);

Resources