Custom qml view - c++

Can I create some custom view? I have some model(written in C++ inheriting QAbstractListModel), which I use in ListView and GridView. When I do some changes in C++, I can just emit dataChanged signal to update my views. Can I connect some QML properties to data from model? Image.source for example?
EDIT 1
I have QAbstractListModel subclass. It contains data about some files. I have created ListView in the left of my main window. Click on some row should change view in the right working area. Working area contains detailed information about each file. So, how can I implement this?

You can access whatever part of your C++ class you expose as a property:
class MyModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QString source READ source WRITE setsource NOTIFY source Changed)
public:
QString source();
void setSource(QString s);
signals:
void sourceChanged();
};
Register the type:
qmlRegisterType<MyModel>("Stuff", 1, 0, "MyModel");
MyModel model
QQmlContext *ctxt = rootContext();
ctxt->setContextProperty("myModel", &model);
Then in QML:
import Stuff 1.0
Image {
source: myModel.source
}

Related

How can I interact with html elements use QT

For example, I have a simple HTML page with button and label (or something else). How can I change the text in label (or something else) and catch the button click use QT.
I try to use QWebEngineView to show html, but I don`t know how to interact with elements from QT modul, just change the url, but I dont think its a better way
To be able to interact with HTML rendered with QWebEngine you need to use QWebChannel. You can find the basic guidelines at Qt WebChannel JavaScript API page.
To implement intercommunication with JavaScript in your HTML page you need:
Add Qt += webchannel in your project file
Implement a QObject derived class that should be a proxy between C++ and JavaScript. The simpliest way to make it usable in JavaScript is to create getters, setters and signals for the values you intend to use in JavaScript, and expose them as Q_PROPERTY.
Example:
class ProxyClass: public QObject
{
Q_OBJECT
Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged)
public:
explicit ProxyClass(QObject *parent = nullptr);
QString value() const;
void setValue(const QString &aValue);
signals:
void valueChanged(const QString &aValue);
};
Set HTML to QWebEngineView with QWebEngineView::setHtml, instantiate your "proxy" class and create QWebChannel for the page (note that you can register multiple objects in QWebChannel). Example:
//create QWebEngineView and set HTML from resources
auto webView = new QWebEngineView;
QFile htmlFile(":/page.html");
htmlFile.open(QIODevice::ReadOnly);
QString html = htmlFile.readAll();
webView->setHtml(html);
//create and set up the instance of your "proxy" class
auto proxy = new ProxyClass;
//create QWebChannel and set it for the page
QWebChannel *webChannel = new QWebChannel(webView->page());
webChannel->registerObject(QStringLiteral("proxy"), proxy);
webView->page()->setWebChannel(webChannel);
Embed qwebchannel.js file in HTML. File is located at <Qt installation directory>/Examples/Qt-<version>/webchannel/shared directory. You can include it in application resources and embed in HTML with <script type="text/javascript" src="qrc:/qwebchannel.js"></script>
Create onload event handler in HTML and initialize QWebChannel in it. Example:
function loaded() {
new QWebChannel(qt.webChannelTransport, function (channel) {
<!--get and assign "proxy"-->
window.proxy = channel.objects.proxy;
<!--now you can-->
<!--get values-->
let proxyValue = proxy.value;
<!--connect signals-->
proxy.valueChanged.connect(() => {
...
});
});
}
function someFunction(newValue) {
<!--set values-->
proxy.value = newValue;
}
...
<body onload="loaded()">...</body>
Once you initialized a web channel and assigned "proxy" object to the window object, you are free to use it everywhere in JavaScript.

How to pass a model to Playlist in qml?

I have this model which holds the URL of the songs
#ifndef PLAYLISTITEM_H
#define PLAYLISTITEM_H
#include<QUrl>
#include <QObject>
class PlaylistItem : public QObject
{
Q_OBJECT
Q_PROPERTY(QUrl source READ source CONSTANT)
public:
explicit PlaylistItem(QUrl& source, QObject *parent = nullptr);
QUrl source() const;
signals:
public slots:
private:
QUrl m_source;
};
#endif // PLAYLISTITEM_H
I have a SongManager class which sets the data to this model and I have set the property in the main.cpp like this
SongManager manager;
ctxt->setContextProperty("manager", &manager);
When I access the model in QML like this
Audio {
id: music_player;
autoPlay: false;
playlist: manager.getSongListByAlbumName("someAlbumName", true)
}
i get this error,
Unable to assign QJSValue to ::QDeclarativePlaylist*
Why did, I get this error, what should I do if I want to override QML elements like PlayListItem with my own model?
I have this model which holds the URL of the songs
The code that follows is not a model by any QML definition of the term.
Audio expects a Playlist element, it doesn't say anything about just about any models, even if you had one. Just because a Playlist can be used as a model doesn't necessarily mean any model can be used as a playlist. But even if that was possible, surely it would require a model with a source role, not an object with a source property.
What manager.getSongListByAlbumName() returns is at this point a mystery, so only a psychic would be able to answer the question as it is.
Assuming manager.getSongListByAlbumName() returns some sort of list that can be iterated from QML, you can use that to populate a Playlist by using the respective methods. I presume it will be possible to directly pass a QList<QUrl> to Playlist.addItems(sources) and just have it work as this particular container type is automatically converted for QML.

In Qt I want to make my model generation in a separate class for a QTableView

As a C/C# programmer I'm new to Qt and have little experience in C++.
What I want to do is 'making' the model of a QTableView in the class containing my data. In C# I could return a DataSet from a static method in a class containing all my stuff concerning this data, and bind this dataset to my table or list.
public class Books
{
//properties
...
//construtors etc...
...
static DataSet BookData()
{
// fill my dataset
return myDataSet;
}
}
In the main program I then bind my DataSet with the control I wanted to use
Is there a way to do so in Qt / C++ doing the same so that I can write something like:
QSqlTableModel* Books::BookData()
{
// Create an QSqlTableModel
// Fill it with my data
return model; // or whatever is possible
}
in the main program:
...
ui->tvBooks->setModel(BookData());
...
And this with correct garbage cleaning or is this wishful thinking...
tnx
In Qt, this is generally done as follows:
Have a model that contains your data.
Invoke setModel on the view, letting the view display what's in the model.
Qt has two general approaches to models:
Use a concrete model and populate it with data. Such models include QStringListModel, QStandardItemModel and the models that interface databases, such as QSqlTableModel.
Create a class that derives from one of the base model classes, such as QAbstractListModel, QAbstractTableModel or QAbstractItemModel. Reimplement relevant virtual methods to implement your own model.
In your case, you can, for example:
Make the Books class have a QStandardItemModel as a member, and use it to store the book data. Do not store the data outside of that model. That class should expose the model to outside, and you can then set it on a view. This will be the easier approach, as you don't need to reimplement the model yourself.
If you wish to have the flexibility of SQL available to access the data, you can also use an in-memory SQLITE database, and expose it via QSqlTableModel, QSqlQueryModel or QSQLRelationalTableModel. Other than that, the approach would be as above.
(your answer) Have a method that returns a newly created static model.
Let the Books class inherit QAbstractTableModel. This requires you to understand the semantics of Qt's models, and is a bit harder.
If you wish to use static models, such as QSqlQueryModel, created on the fly each time the database contents change, you can easily leverage QObject's compositeness.
To manage the model's lifetime, it can make itself a view's child automatically, and delete any other instances that are also that view's children:
class Books {
...
static QSqlQueryModel * setModelOn(QAbstractItemView * view) {
Q_ASSERT(view);
for (auto child : view->findChildren<QSqlQueryModel>())
delete child;
auto model = new QSqlQueryModel(view);
model->setQuery("SELECT name, pagecount FROM books");
...
view->setModel(model);
return model;
}
};
[SOLVED]
What I did to solve the case:
class Books
{
static void* GetBookData(QTableView *model)
{
model->setTable("books.books");
model->select();
...
}
};
in the library
And:
...
QTableView *view = new QTableView;
...
Books::GetBookData(view);
ui->myCombobox->setModel(view);
...
delete view;
...
in the main program.

QTableView real-time filtering

My situation looks like this: I have QTableView and LineEdit. I'd like to show data which contains value in LineEdit in real time. I guess I should use QSortProxyFilterModel, but I don't know how to do that. I wrote this:
void MainWindow::on_lineFind_textEdited(const QString &arg1)
{
QSortFilterProxyModel proxy;
proxy.setSourceModel(ui->tableView->model());
proxy.setFilterRegExp(arg1);
QModelIndex index=proxy.mapToSource(proxy.index(0,0));
if(index.isValid())
{
ui->tableView->selectionModel()->select(index,QItemSelectionModel::Select | QItemSelectionModel::Rows);
ui->tableView->scrollTo(index,QAbstractItemView::EnsureVisible);
}
}
But it doesn't work (no change visible). Example how it should work: Clementine Player playlist.
You create QSortFilterProxyModel and destroy it immediately in your function. It's incorrect use. You need to create one object of QSortFilterProxyModel (maybe using new), then call QTableView::setModel for attaching proxy model to your view. After that changes will take effect.
In the initialization:
ui->setupUi(this);
my_model = new QStandardItemModel(); // or any other model class
proxy_model = new QSortFilterProxyModel();
ui->table_view->setModel(proxy_model);
proxy_model->setSourceModel(my_model);
In textEdited slot:
proxy_model->setFilterRegExp(arg1);

Qt, get data inside a child widget from another child widget

I create new cad widget in my mainwindow:
glWidget = new MeshViewerWidget(this);
and then my text view widget:
tbl = new tableView( this );
in my mainwindow i can get my mesh with:
glWidget->mesh();
How do i get it in my tableview.cc? ty
You could use the findChildren function of QObject and get a list of all children of a widget that can be casted to the given type. Eg
QList<QTableView*> allTableViews = glWidget->findChildren<QTableView *>();
// Iterate in order to find the table view either by checking the name, the parent etc....
Another approach would be the one Simon suggests, subclassing and adding public access function to the members you want to be reachable from top level widgets.