In this piece of code, edit_sclratio is a QLineEdit. How do I use it's validator as a QDoubleValidator without using an old-style cast:
(QDoubleValidator*)_ui->edit_sclratio->validator() //This works fine
But I want to use proper casting and static, dynamic, const and reinterpret cast doesn't work. The error is always it "casts away qualifiers.
QDoubleValidator* validator = static_cast<QDoubleValidator*>(_ui->edit_sclratio->validator());
The error is always it "casts away qualifiers.
Here, it's talking about const qualifiers.
QLineEdit::validator() returns a const QValidator*, so you must cast it to a const QDoubleValidator*.
Note: I suggest you form the habit of using qobject_cast<> for classes that inherit QObject (like QValidator). It has the added benefit of returning a nullptr if you try to cast to the wrong type; this lets you do run-time error checks.
Related
In Qt, it is common to see something similar to the following:
QSettings obj3(QSettings::SystemScope, "MySoft", "Star Runner");
The important bit is the QSettings::SystemScope, which is an enum.
I want to have a settings provider (pay no attention to the previous example here, it has nothing to do with the following), with a get/set property.
Settings.set(Settings::refreshRate)
The refreshRate has to link to a key (string), and a default value (variant).
Should I make an enum and two dicts for the key and default values, or make a struct and a whole bunch of variables that encapsulate the settings I need? Should I try something else?
Thanks!
Edit!
This is what I did.
// Interface
class Settings {
public:
static QVariant get(Setting setting);
static void set(Setting setting, QVariant value);
const static Setting serverRefreshRate;
const static Setting serverReportTimeout;
};
// Implementation
const Setting Settings::serverRefreshRate = { "server/refreshRate", 10000 };
const Setting Settings::serverReportTimeout = { "server/reportTimeout", 1000 };
Well I guess since you're using enum which most likely will be easily castable to numbers from to 0 to N-1 I guess just storing variants and strings in two vectors or one vector of pairs would work just fine.
There's also another question though -- how to initialize all of that and how you will be adding new settings to it. I can suggest two methods - first one writing a bunch of function calls with arguments: enum, string, variant. Thus way though if programmer adds another value to enum he can forget to call initializing function. The other way is to create function (or maybe two) which will do switch on all enum values (without default case) and will return pair of string and variant. You can turn on the compiler warning about all enum values being processed in switch and thus way control if you forget to implement some of them in that function. And then initialize your structures using loop on all of enum values. These initializing functions should be called somewhere near the beginning of your program (before reading settings initially).
Well, that's my thoughts on it, you are free to try some different ways though.
I've been fighting with this all day long and I've tried passing a QString, a std::string, and a char* in many many different fashions, but if I pass it so that I can modify the parameter's value inside the library function then it SEGFAULTs. If I copy the library function, line for line, into the main app, I can pass references all day long as params and change their values inside the functions.
Here is the stripped down version of my function inside the library.
I have literally removed all code except for this line.
MySQLLib::ExecuteQuery(const QString& query, QString& results)
{
results = "Changed the value of this parameter.";
}
Here is the calling code from the main application.
bmdbTest is an instance of the above MySQLLib class...
All the other code in my library and application works. It just won't let me pass references to ANYTHING to my library.
MySQLProj::pbExecuteQuery_Click()
{
QString x = "Hello.";
bmdbTest->ExecuteQuery("SELECT ttid from test_table", x);
ui_MySQLProj1.textEdit->setText(x);
}
It SEGFAULTs on the bmdbTest->ExecuteQuery call.
I've even tried a simple int& as a parameter with no success.
I can however pass params as const QString& without issue. I just can't modify the param's value that way.
EDIT: I just figured it out. Thank you to "paxdiablo" for suggesting I check my variables for null or invalid pointers. I was really tired last night and I can't believe I missed this.
I just found the problem and I feel like a complete idiot. You mentioned about bmdbTest being null or invalid. The value of bmdbTest was fine as all my other functions worked fine, but when I was calling ExecuteQuery() I was passing the query string from the value in a QLineEdit from my GUI window like this.
bmdbTest->ExecuteQuery(leQuery->text(), resultString);
The leQuery->Text() was actually the problem as I must access leQuery like this.
bmdbTest->ExecuteQuery(ui_MySQLProj1.leQuery->text(), resultString);
You may want to check the value of bmdbTest itself. It may be null or an invalid pointer.
That seems to be indicated by the fact it's faulting on that line. If there were something suspect about the parameters, I would expect it to fault within the ExecuteQuery function.
You should be able to find out exactly where the crash is by putting suitable debug statements (with flushing) on either side of the results = ... and bmdbTest->ExecuteQuery(...) lines (or use a debugger if you have one).
I'm trying to use QtConcurrent::map to run this function
//This function is used through QtConcurrent::map to create images from a QString path
void MainWindow::createQImage(QString* path) {
//create an image from the given path
QImage* t = new QImage(*path);
imageList->append(t);
}
on this container/sequence (declared in the mainwindow header and initialized in the mainwindow constructor)
QList<QImage *> *imageList = new QList<QImage *>;
Here's the code I'm trying to run
QFutureWatcher<void> futureWatcher;
futureWatcher.setFuture(QtConcurrent::map(imageList, &MainWindow::createQImage));
and here are the errors I'm getting:
request for member 'begin' in 'sequence', which is of non-class type 'QList<QImage*>*'
request for member 'end' in 'sequence', which is of non-class type 'QList<QImage*>*'
I need the "createQImage" function to be run for every element in "imageList," which can reach into the thousands. I believe the problem to be with the first parameter to the map function. And from what I've read, it may have to do with compatibility. There isn't much sample code online that I was able to relate to. I'm new to Qt and not the most experienced of programmers but I'd appreciate some help and feedback.
Alternatively, is there better way to do this using QtConcurrent?
Thanks in advance!
QtConcurrent::map wants a sequence as its first argument. You passed it a pointer to a sequence.
If you do
futureWatcher.setFuture(QtConcurrent::map(*imageList, &MainWindow::createQImage));
it should be happy.
Note that the compiler was reasonably clear about what the problem was. Take the time to read the errors carefully, they're usually not as cryptic as they perhaps at first seem. In this case it was telling you that the argument you passed was not of a class type. A quick look at the argument type at the end of the error reveals that it is a pointer.
QList, QImage, QString are Copy-On-Write types (see other Qt implicitly shared types), so you shouldn't use pointers to these types because they are basically already smart pointers.
And if you remove all pointers from your code, it should also fix the main problem.
I have a QListWidget of calendars. Each QListWidgetItem is logically associated with an instance of Calendar, which is a class that belongs to the Model side of the application.
Can I store this association in the form of a pointer using QListWidgetItem::setData? When I attempt to do this, I get the following error:
error: 'QVariant::QVariant(void*)' is private
There is another constructor for void*: QVariant::QVariant(int typeOrUserType, const void * copy) where you should pass an unique integer to represent the pointer type.
But as stated by the documentation, you could declare your pointer type with Q_DECLARE_METATYPE(Calendar*) and use QVariant::fromValue<Calendar*>(...) and QVariant::value<Calendar*>() to store and retrieve the value.
Or instead, because you are using a QListWidget instead of a regular model, you can just subclass QListWidgetItem, and add a Calendar* member variable with the required accessors, to avoid the overhead of using QVariant.
I would suggest looking at this solution as well, which I think is quite elegant:
(there are minor syntax errors, but you will spot them quickly or the compiler will issue an error)
https://web.archive.org/web/20171025163314/http://blog.bigpixel.ro/2010/04/storing-pointer-in-qvariant/
The QtWebKit Bridge documentation states the following -
Compound (JSON) objects JavaScript
compound objects, also known as JSON
objects, are variables that hold a
list of key-value pairs, where all the
keys are strings and the values can
have any type. This translates very
well to QVariantMap, which is nothing
more than a QMap of QString to
QVariant. The seamless conversion
between JSON objects and QVariantMap
allows for a very convenient way of
passing arbitrary structured data
between C++ and the JavaScript
environment. The native QObject has to
make sure that compound values are
converted to QVariantMaps and
QVariantLists, and JavaScript is
guaranteed to receive them in a
meaningful way. Note that types that
are not supported by JSON, such as
JavaScript functions and
getters/setters, are not converted.
Does this mean that, while JavaScript is able to read a QVariantList, it is unable to modify it?
I've tried adding a getter and setter for test purposes -
Q_PROPERTY( QVariantMap Settings READ GetShadowSettings WRITE SetShadowSettings )
The getter function is being called when the JavaScript wants to access any data from the QVariantMap. Unfortunately, when the JavaScript attempts to update the QVariantMap, the getter function is called again (rather than the setter function).
I can modify the data using a simple helper function such as -
Q_INVOKABLE void Update( QString key, QVariant value ) {
settings[key] = value;
}
I was just wondering if there was a way of doing this without the need for a helper function?
I use QVariantMap for PhantomJS and it works just fine. For example, WebPage#viewportSize is just QVariantMap in its implementation. The usual problem is you can't try to update one of its property only, e.g. viewportSize.width = 300. You have to pass back an object, e.g.:
viewportSize = { width: 300, height: 200 }.
If you need to able to do the former, the only (ugly) workaround that might work is to create a helper object, e.g. Size in the above case, which has the proper setter and getter for the individual property and handle the housekeeping of bridging.