This is one of my first projects using QML: I started making a simple game character and a few rooms, and to make the walls'hitboxes I stored them all into a file and included a FileIO class I saw in this site, adapted to return the entire file instead of just one line.
The program, though, tells me it isn't able to open the file (I have put it in the project's directory)
//main.qml (ignore line 5)
import QtQuick 2.15
import QtQuick.Shapes 1.12
import FileIO 1.0
// Whats this? UwU a byzantiuwm?!?!!? UwU i wove byzantiuwm, especiwwawwy in the #memes channew wewe byzantiuwm is the tawk of ze town! OwO
Rectangle {
width: 639
height: 480
id: sus // I hate myself
color: "#00ff00"
Shape {
property string d: "S"
property int room: 1
id: player
x: xPos
y: yPos
z: 1
visible: true
property int xPos: 297
property int yPos: 219
parent: sus
width: 45
height: 45
focus: true
Keys.onPressed:
{
if(event.key === Qt.Key_Down){
yPos+=3; d="S"
}
if(event.key === Qt.Key_Up){
yPos-=3; d="N"
}
if(event.key === Qt.Key_Left){
xPos-=3; d="W"
}
if(event.key === Qt.Key_Right){
xPos+=3; d="E"
}
event.accepted = true;
}
ShapePath{
strokeColor: "transparent"
fillColor: "transparent"
PathLine{x:45 ;y: 0}
PathLine{x:45 ;y:45}
PathLine{x: 0 ;y:45}
}
Image {
id: sprite
parent: player
width: parent.width
height: parent.height
smooth: false
source: "Player/Player_" + player.d + ".png"
}
}
Image {
id: background
x: 0
y: 0
z: 0
width: 639
height: 480
visible: true
smooth: false
parent: sus
source: "Rooms/" + player.room + ".png"
fillMode: Image.Stretch
}
Shape {
id: wallHitBox
x: 0
y: 0
z: 50
width: sus.width
height: sus.height
//visible: false
FileIO{
id: fileReader
source: "Rooms/Hitboxes_or_something.txt"
onError: {console.log(msg)}
}
property var the: fileReader.read()
ShapePath{
strokeColor: "transparent"
fillColor: "blue" //"transparent"
PathSvg{
path: wallHitBox.the[player.room];
}
}
}
}
//fileio.cpp
#include "fileio.h"
#include <QFile>
#include <QTextStream>
FileIO::FileIO(QObject *parent) :
QObject(parent)
{
}
QVector<QString> FileIO::read()
{
if (mSource.isEmpty()){
emit error("source is empty");
return QVector<QString>();
}
QFile file(mSource);
QVector<QString> fileContent;
if ( file.open(QIODevice::ReadOnly) ) {
QString line;
QTextStream t( &file );
do {
line = t.readLine();
fileContent.resize(fileContent.size()+1);
fileContent[fileContent.size()] = line;
} while (!line.isNull());
file.close();
} else {
emit error("Unable to open the file");
return QVector<QString>();
}
return fileContent;
}
bool FileIO::write(const QString& data)
{
if (mSource.isEmpty())
return false;
QFile file(mSource);
if (!file.open(QFile::WriteOnly | QFile::Truncate))
return false;
QTextStream out(&file);
out << data;
file.close();
return true;
}
#define FILEIO_H
#include <QObject>
class FileIO : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(QString source
READ source
WRITE setSource
NOTIFY sourceChanged)
explicit FileIO(QObject *parent = 0);
Q_INVOKABLE QVector<QString> read();
Q_INVOKABLE bool write(const QString& data);
QString source() { return mSource; };
public slots:
void setSource(const QString& source) { mSource = source; };
signals:
void sourceChanged(const QString& source);
void error(const QString& msg);
private:
QString mSource;
};
#endif // FILEIO_H
Can someone please help me?
I made my own QQuickItem, which I draw using the updatePaintNode method (using the scenegraph). In a qml File I add this item as a child to a Rectangle:
Rectangle {
anchors.centerIn: parent
width: parent.width/2.
height: parent.height/2.
border.color: "#000000"
clip: true
MyItem {
id: myitem
anchors.centerIn: parent
width: parent.width
height: parent.height
MouseArea {
anchors.fill: parent
onWheel: {
if (wheel.modifiers & Qt.ControlModifier) {
parent.scale = parent.scale+ 0.2 * wheel.angleDelta.y / 120;
if (parent.scale < 1)
parent.scale = 1;
}
}
}
}
}
As you can see, I added a zoom function and set
clip: True
for the rectangle. However, when I zoom, my item is not clipped at the Rectangle but extends beyond it. What would be the correct way to do clipping?
Edit: Here is the content of the cpp file for MyItem
MyItem::MyItem(QQuickItem *parent): QQuickItem(parent)
{
setFlag(QQuickItem::ItemHasContents,true);
// code to initialize xdata, ydata, xmax, ymax
}
QSGNode *MyItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) {
QSGGeometryNode *mypath = static_cast<QSGGeometryNode*>(oldNode);
if(!mypath) {
mypath = new QSGGeometryNode;
mypath->setFlag(QSGNode::OwnsMaterial,true);
mypath->setFlag(QSGNode::OwnsGeometry,true);
}
QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(),_xdata.size());
QSGGeometry::Point2D *points = geometry->vertexDataAsPoint2D();
for(int i=0;i<_xdata.size();i++) {
points[i].x = _xdata[i]/_xmax*width();
points[i].y = _ydata[i]/_ymax*height();
}
geometry->setLineWidth(2);
geometry->setDrawingMode(GL_LINE_STRIP);
mypath->setGeometry(geometry);
QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
material->setColor(Qt::blue);
mypath->setMaterial(material);
return mypath;
}
and here is the header file:
#include <QQuickItem>
#include <vector>
class MyItem : public QQuickItem
{
Q_OBJECT
public:
MyItem(QQuickItem *parent = 0);
private:
std::vector<double> _xdata;
std::vector<double> _ydata;
double _xmax;
double _ymax;
signals:
public slots:
protected:
QSGNode * updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) override;
};
I want to take a screen shot using the code
QImage img = currentView_->grabWindow();
and i want to display this screen shot on my GUI using QML.
How to do this ?
If you want to transfer an image from C++ to QML the best way I guess is QQuickImageProvider. The small example bellow is maybe a bit different from what you want but anyway:
QQuickImageProvider class:
#ifndef IMAGEPROVIDER_H
#define IMAGEPROVIDER_H
#include <QQuickImageProvider>
#include <QQuickView>
#include <QImage>
class ImageProvider : public QObject, public QQuickImageProvider
{
Q_OBJECT
public:
ImageProvider(QObject *parent = 0, Flags flags = Flags());
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
protected:
QMap<int, QImage> m_images;
public slots:
void makeScreenshot();
};
#endif // IMAGEPROVIDER_H
#include "imageprovider.h"
ImageProvider::ImageProvider(QObject *parent, Flags flags) :
QQuickImageProvider(QQmlImageProviderBase::Image, flags),
QObject(parent)
{
}
QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
bool ok = false;
QImage img = m_images[id.toInt(&ok)];
return img;
}
void ImageProvider::makeScreenshot()
{
QQuickWindow *view = static_cast<QQuickWindow *>(sender());
static int pos = 0;
QImage img = view->grabWindow();
m_images.insert(pos,img);
QVariant returnedValue;
QMetaObject::invokeMethod(view, "setImage",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, pos++));
}
Registering it in main.cpp:
QQmlApplicationEngine engine;
ImageProvider *imageProvider = new ImageProvider();
engine.addImageProvider(QLatin1String("screenshots"), imageProvider);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QQuickWindow *view = dynamic_cast<QQuickWindow *>(engine.rootObjects().at(0));
QObject::connect(view, SIGNAL(getScreenshot()),
imageProvider, SLOT(makeScreenshot()));
Usage:
import QtQuick 2.7
import QtQuick.Window 2.0
Window {
id:container
width: 600
height: 600
visible: true
signal getScreenshot()
Repeater {
model: 20
delegate: Rectangle {
x: Math.random() * 500
y: Math.random() * 500
width: Math.random() * 50 + 50
height: width
radius: width / 2
color: Qt.rgba(Math.random(),Math.random(),Math.random(),1)
}
}
Text {
id: txt
anchors.centerIn: parent
text: "Click me"
}
Rectangle {
id: rect
anchors.centerIn: parent
width: 0
height: 0
border.width: 5
border.color: "black"
Image {
id: img
anchors.fill: parent
anchors.margins: 5
source: ""
fillMode: Image.PreserveAspectFit
}
ParallelAnimation {
id: anim
PropertyAnimation {
property: "width"
target: rect
from: 0
to: 200
duration: 500
}
PropertyAnimation {
property: "height"
target: rect
from: 0
to: 200
duration: 500
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
txt.visible = false;
container.getScreenshot();
}
}
function setImage(id)
{
img.source = "image://screenshots/" + id;
anim.running = true;
}
}
I have QML TableView with QSqlQueryModel. I need to select any row and get data from every column of table to separate TextField.
Here is abonentstable.h:
#pragma once
#include <QObject>
#include <QSqlQueryModel>
class AbonentsSqlModel : public QSqlQueryModel
{
Q_OBJECT
public:
explicit AbonentsSqlModel(QObject *parent = 0);
void setQuery(const QString &query, const QSqlDatabase &db = QSqlDatabase());
QVariant data(const QModelIndex &index, int role) const;
QHash<int, QByteArray> roleNames() const { return m_roleNames; }
private:
void generateRoleNames();
QHash<int, QByteArray> m_roleNames;
};
abonentstable.cpp:
#include "abonentstable.h"
#include <QSqlRecord>
#include <QSqlField>
AbonentsSqlModel::AbonentsSqlModel(QObject *parent) : QSqlQueryModel(parent)
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("data_base.sqlite");
db.open();
}
void AbonentsSqlModel::setQuery(const QString &query, const QSqlDatabase &db)
{
QSqlQueryModel::setQuery(query, db);
generateRoleNames();
}
void AbonentsSqlModel::generateRoleNames()
{
m_roleNames.clear();
for( int i = 0; i < record().count(); i ++) {
m_roleNames.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8());
}
}
QVariant AbonentsSqlModel::data(const QModelIndex &index, int role) const
{
QVariant value;
if(role < Qt::UserRole) {
value = QSqlQueryModel::data(index, role);
}
else {
int columnIdx = role - Qt::UserRole - 1;
QModelIndex modelIndex = this->index(index.row(), columnIdx);
value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
}
return value;
}
Table.qml:
TableView {
id: table
model: abonents
....
TableViewColumn {
delegate: Text {
text: " " + model.name + " " + model.surname
font.pointSize: 20
}
width: 575
}
TableViewColumn {
delegate: Text {
text: " " + model.phone
font.pointSize: 20
}
width: 575
}
TableViewColumn {
delegate: Text {
text: " " + model.ip_address
font.pointSize: 20
}
width: 525
}
}
And some text fields:
TextField {
id: leftText
}
TextField {
id: centerText
}
TextField {
id: rightText
}
This sqlite table has 4 columns, and I need to get data from selected row to those text fields: 2 columns to left, 1 to center and 1 to right.
When the user clicks a valid row it is emitted the clicked(int row) signal. Then, you can get the values for that row, format the text depending on your requirements and set the values in the three TextField. For example, in your case:
TableView {
id: table
model: abonents
... (your TableViewColumn components) ...
onClicked: {
leftText.text = abonents.get(row).name + " " + libraryModel.get(row).surname;
centerText.text = abonents.get(row).phone;
rightText.text = abonents.get(row).ip_address;
}
}
Please, let me please use my own answer to show you a complete example:
import QtQuick 2.2
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
ApplicationWindow {
id: window
visible: true
title: "Table View Example"
TableView {
y: 70
width: 500
TableViewColumn {
role: "title"
title: "Title"
width: 100
}
TableViewColumn {
role: "author"
title: "Author"
width: 100
}
TableViewColumn{
width: 300
delegate: Text {
text: model.title + " " + model.author
font.family: "Courier New"
font.pixelSize: 18
color: "red"
}
}
onClicked: {
leftText.text = libraryModel.get(row).title + " " + libraryModel.get(row).author;
centerText.text = libraryModel.get(row).title;
rightText.text = libraryModel.get(row).author;
}
model: libraryModel
ListModel {
id: libraryModel
ListElement {
title: "A Masterpiece"
author: "Gabriel"
}
ListElement {
title: "Brilliance"
author: "Jens"
}
ListElement {
title: "Outstanding"
author: "Frederik"
}
}
}
TextField {
id: leftText
}
TextField {
id: centerText
anchors.left: leftText.right
}
TextField {
id: rightText
anchors.left: centerText.right
}
}
Is it possible to have a model view (such as ListView or GridView) in a delegate of another model view?
I'm using a ListView (LV1) whose delegate also has a ListView (LV2). Everything before and after LV2 is displayed correctly (and that's in the delegate of LV1). However, nothing is shown in LV1.
My model is from this: http://qt-project.org/wiki/How_to_use_a_QSqlQueryModel_in_QML . I suppose that the SQL query is correct since it returns the correct information when ran externally to Qt. According to debug messages, that all queries is clearly executed.
I have two queries, one being updated with the other. That works good.
Figure #1 shows the debug messages, and it points out that the QML does call the data function and information is indeed returned from the database.
Figure #2 shows the QML window at the time of figure #1: we can clearly see that the layout is messed up and nothing is shown.
Verbatim #1 is the QML code.
Verbatim #2 is an excerpt of the main which shows that I connect the main model to the secondary model though a signal called updateBindings.
Verbatim #3 is my updated SqlQueryModel. The main difference with the tutorial is the signal and slots.
Verbatim #4 is for reference, since this class is used in verbatim #3.
Any input is valued, I've been struggling with this for a few days now. Thanks.
Verbatim #1 (QML):
import QtQuick 1.1
import "Styles"
Rectangle {
id : window;
width : 750
height : 500
signal searchSignal(string msg)
signal resetSignal()
property variant subtypes: {"S":"Status (digital)", "V":"Value (analog)"}
property variant phases: {'66': 'Final Mass Properties', '67': 'Final Thruster Aignment/Solar Array Inst.', '60': 'Final Functional Performance', '114': 'Maneuver (Wheel Mode) Overlay (LTO)', '88': 'Troubleshooting Test Phase 9', '89': 'Troubleshooting Test Phase 10', '111': 'Battery 1 Reconditioning Overlay (LTO)', '110': 'Battery Recharge Overlay (LTO)', '113': 'Maneuver (SK Mode) Overlay (LTO)', '112': 'Battery 2 Reconditioning Overlay (LTO)', '68': 'Flight Battery Functional', '83': 'Troubleshooting Test Phase 4', '80': 'Troubleshooting Test Phase 1', '81': 'Troubleshooting Test Phase 2', '86': 'Troubleshooting Test Phase 7', '87': 'Troubleshooting Test Phase 8', '84': 'Troubleshooting Test Phase 5', '85': 'Troubleshooting Test Phase 6', '24': 'Post T/V Performance ( Ambient)', '26': 'Alignments - Pre Dynamics', '27': 'Antenna Installation', '20': 'Cold (Equinox) Functional Plateau', '21': 'Transition Monitor (cold to hot)', '22': 'Hot ( Winter Solstice)', '82': 'Troubleshooting Test Phase 3', '28': 'Solar Array Installation', '40': 'CATR', '41': 'ESD (PFM Only)', '1': 'North Panel Electrical integration', '3': 'SSM/Bus Module Electrical Integration', '2': 'South Panel Electrical integration', '5': 'South and bus Electrical Integration', '4': 'North and Bus Electrical integration', '6': 'S/C Electrical Integration', '75': 'Hazardous Processing Facility Operations', '39': 'Final Alignment Verif. CATR Preps', '77': 'Launch Complex Performance', '76': 'HPF Payload testing', '108': 'Lunar Eclipse Event Overlay (LTO)', '109': 'Battery Discharge Overlay (LTO)', '70': 'Launch Base Functional Performance', '102': 'On Orbit', '103': 'Station Keeping', '100': 'Prime Shift Orbit Raising', '101': 'Off Shift Orbit Raising', '106': 'Quiescent Non-Eclipse State of Health (LTO)', '107': 'Earth Eclipse Season Overlay (LTO)', '104': 'Eclipse', '105': 'Post Eclipse', '10': 'Panel RF Testing', '13': 'Integrated System Reference Performance', '12': 'End to End Satting', '15': 'Transition Monitoring (Ambient to Hot Solstice)', '14': 'Pre Thermal Vacuum performance (Ambient)', '16': 'Summer Solstice Functional Plateau', '18': 'Transition Monitoring (Hot to Cold)', '31': 'Sine Vibration', '30': 'Acoustic Vibration', '36': 'Post Dynamics Performance', '35': 'Deployments', '34': 'Launch Vehicle Adapter Fit Check', '65': 'Propulsion Global Helium'}
ListView {
anchors.fill: parent
focus: true
highlightRangeMode: ListView.StrictlyEnforceRange
orientation: ListView.Horizontal
snapMode: ListView.SnapOneItem
model: tcModel
delegate: Component {
Item {
id: item
width: window.width; height: window.height
Flickable {
id: mainScrollView
contentHeight: parent.height
contentWidth: parent.width
anchors.fill: parent
clip: true
focus: true
interactive: true
Column{
id: dataCol
spacing: 10
/* Buttons */
Row{
width: window.width
Button{
text: "Go"
action.onClicked: searchSignal("TLM_NO LIKE '" + num.text + "%'")
bgColor: "lightgreen"
width: window.width/10; height: window.width/30
}
Button{
text: "Reset"
action.onClicked: resetSignal()
bgColor: "lightgrey"
width: window.width/10; height: window.width/30
}
}
/* */
Grid{
columns: 5
spacing: 10
Text {
text: "Mnemonic"
font.bold: true
}
Text {
text: "Name"
font.bold: true
}
Text {
text: "Type"
font.bold: true
}
Text {
text: "Subtype"
font.bold: true
}
Text {
text: "Category"
font.bold: true
}
/* NEW LINE */
TextEdit {
id: num
text: TLM_NO
}
Text {
text: TLM_NAME
}
Text {
text: TLM_TYPE
}
Text {
text: (SUBTYPE ? subtypes[SUBTYPE] : "Unknown")
}
Text {
text: TLM_CATEGO
}
} /* End grid */
Separator{}
Text{
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: "<u>Limits</u>"
id: limitLabel
}
/* Limits */
ListView {
//anchors.top: limitLabel.bottom
header:
Row{
height: 30
clip: true
anchors.margins: 4
Text {
text: "Phase name"
font.bold: true
}
Text {
text: "Red low"
font.bold: true
}
Text {
text: "Yellow low"
font.bold: true
}
Text {
text: "Yellow high"
font.bold: true
}
Text {
text: "Red high"
font.bold: true
}
}
delegate: Item {
id: delegate
width: delegate.ListView.view.width;
height: 30
clip: true
anchors.margins: 4
Row {
anchors.margins: 4
anchors.fill: parent
spacing: 4;
Text {
text: PHASE_NO?phases[PHASE_NO]:"N/A"
}
Text {
text: CRIT_LO?CRIT_LO:"N/A"
}
Text {
text: NOM_LO?NOM_LO:"N/A"
}
Text {
text: NOM_HI?NOM_HI:"N/A"
}
Text {
text: CRIT_HI?CRIT_HI:"N/A"
}
}
}
model: limitModel
height: window.height / 3
} /* End limits grid view*/
Separator{}
Text{
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: "end limits"
}
}/* End column*/
}
}
}
}
}
Verbatim #2 (main.cpp , excerpt):
/* Let's create all the models associated with this given user form.*/
/* We need the viewer to connect all the signals and to set context properties.*/
QmlApplicationViewer viewer;
SqlQueryModel *mainModel;
QList<SqlQueryModel*>::iterator umIt;
QHash<QString, SqlQueryModel*> modelCnx = QHash<QString, SqlQueryModel*>();
for(umIt = selectedUF.userModels.begin(); umIt != selectedUF.userModels.end(); umIt++){
SqlQueryModel *model = *umIt;
/* Let's go through each binding of the UserModel and connect create the bindings in the model. */
model->exec();
viewer.rootContext()->setContextProperty(model->modelName, model);
/* If this is the selected search model, let's save it to connect the signals later. */
if (model->modelName == selectedUF.searchModel){
mainModel = model;
}else{
QObject::connect(mainModel, SIGNAL(bindedValueChanged(QString, QString, QVariant)),
model, SLOT(updateBindings(QString,QString,QVariant)));
}
}
viewer.setMainQmlFile(QString("qml/" + selectedUF.qml));
QObject::connect((QObject*)viewer.rootObject(), SIGNAL(searchSignal(QString)),
mainModel, SLOT(search(QString)));
QObject::connect((QObject*)viewer.rootObject(), SIGNAL(resetSignal()),
mainModel, SLOT(reset()));
viewer.showExpanded();
return app->exec();
Verbatim #3 (sqlquerymodel.cpp):
#include "sqlquerymodel.h"
SqlQueryModel::SqlQueryModel(QObject *parent) :
QSqlQueryModel(parent)
{
this->modelName = "";
this->query = "";
bindings = QHash<QString, QList<ModelBinding> >();
}
void SqlQueryModel::setQuery(const QString &query, const QSqlDatabase &db)
{
if(query.length() == 0){
this->query = query;
}
QSqlQueryModel::setQuery(query, db);
generateRoleNames();
QSqlError le = this->lastError();
if (le.isValid()){
QString errMsg("Query was:\n%1\n\nError:\n%2");
QMessageBox::critical(0, "Query error", errMsg.arg(query).arg(le.text()));
return;
}
}
void SqlQueryModel::setQuery(const QSqlQuery &query)
{
QSqlQueryModel::setQuery(query);
generateRoleNames();
QSqlError le = this->lastError();
if (le.isValid()){
QString errMsg("Query was:\n%1\n\nError:\n%2");
qDebug() << errMsg.arg(query.lastQuery()).arg(le.text());
/* We're not using a MessageBox because it causes a segfault for some reason. */
//QMessageBox::critical(0, "Query error", errMsg.arg(query.lastQuery()).arg(le.text()));
return;
}
}
/**
* #brief SqlQueryModel::exec This function prepares and executes the query.
*/
void SqlQueryModel::exec()
{
qDebug() << "Executing query on model" << this->modelName;
/* Let's create a QSqlQuery. It will store the query and we'll bind values to it.*/
QSqlQuery sQuery;
/* If we initialize the query with the string, then we CANNOT use bind (won't work and won't show any error).*/
sQuery.prepare(this->query);
/** Now, let's go through all the models associated to this instance.
* For each of them, we'll bind its value. Note that we're avoiding making a copy by using the adresses
* cf. : http://stackoverflow.com/questions/17106243/qt-iterator-not-accessing-the-correct-object
**/
QHash<QString, QList<ModelBinding> >::iterator bindingsIt;
for (bindingsIt = bindings.begin(); bindingsIt != bindings.end(); bindingsIt++){
QList<ModelBinding>::iterator eachBindingIt;
QList<ModelBinding>& curBinding = *bindingsIt;
for(eachBindingIt = curBinding.begin(); eachBindingIt != curBinding.end(); eachBindingIt++){
ModelBinding& binding = *eachBindingIt;
binding.bindToQuery(&sQuery);
}
}
/* Let's not forget to execute this query, or nothing will be displayed in the QML. */
sQuery.exec();
qDebug() << "----------------";
qDebug() << sQuery.lastQuery();
QMapIterator<QString, QVariant> i(sQuery.boundValues());
while (i.hasNext()) {
i.next();
qDebug() << i.key().toAscii().data() << "="
<< i.value().toString().toAscii().data();
}
qDebug() << "----------------";
this->setQuery(sQuery);
}
void SqlQueryModel::generateRoleNames()
{
QHash<int, QByteArray> roleNames;
for( int i = 0; i < record().count(); i++) {
roleNames[Qt::UserRole + i + 1] = record().fieldName(i).toAscii();
}
qDebug() << "Generating role names for" << modelName;
setRoleNames(roleNames);
}
void SqlQueryModel::search(QString str){
QString nQuery (query);
nQuery.append(" WHERE ").append(str);
qDebug() << "Set query to: " << nQuery;
this->setQuery(nQuery);
QSqlError le = this->lastError();
if (le.isValid()){
QString errMsg("An error occurred while loading the file.\n\nQuery was:\n%1\n\nError:\n%2");
QMessageBox::critical(0, "Database error", errMsg.arg(nQuery).arg(le.text()));
}
}
QVariant SqlQueryModel::data(const QModelIndex &index, int role) const
{
QVariant value = QSqlQueryModel::data(index, role);
if(role < Qt::UserRole){
value = QSqlQueryModel::data(index, role);
}else{
int columnIdx = role - Qt::UserRole - 1;
QModelIndex modelIndex = this->index(index.row(), columnIdx);
value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
qDebug() << modelName << ":" << record().fieldName(columnIdx) << "=" << value;
emit bindedValueChanged(modelName, record().fieldName(columnIdx), value);
}
return value;
}
void SqlQueryModel::reset()
{
qDebug() << "Resetting original SQL query to: " << query;
this->setQuery(query);
}
void SqlQueryModel::updateBindings(QString modelName, QString col, QVariant val)
{
/** Now, let's go through all the models associated to this instance.
* We're going to see if the new signal we got is used for this model (for model name and column name).
* If so, we'll assigned it and then we'll execute this query by calling exec().
**/
bool anyValueChanged = false;
QHash<QString, QList<ModelBinding> >::iterator bindingsIt;
for (bindingsIt = bindings.begin(); bindingsIt != bindings.end(); bindingsIt++){
QList<ModelBinding>::iterator eachBindingIt;
QList<ModelBinding>& curBinding = *bindingsIt;
for(eachBindingIt = curBinding.begin(); eachBindingIt != curBinding.end(); eachBindingIt++){
ModelBinding& binding = *eachBindingIt;
if(bindingsIt.key() == modelName && binding.column == col){
binding.value = val;
anyValueChanged = true;
}
}
}
if (anyValueChanged){
this->exec();
}
}
Verbatim #4 (modelbinding.cpp):
#include "modelbinding.h"
ModelBinding::ModelBinding(QString placeholder, QString column, QVariant value)
{
this->placeholder = placeholder;
this->column = column;
this->value = value;
}
void ModelBinding::bindToQuery(QSqlQuery *sQuery)
{
sQuery->bindValue(placeholder, value);
}
The item in your base ListView delegate is sized to the window's height and width. I believe this would effectively hide any other delegates from the root level ListView because the first delegate would take up the entire screen.