C++ string declaration and Qt issue - c++

cpp file:
#include "currency.hpp"
currencyNames[4] = {"gbp","usd","eur","aud"};
QComboBox *box1 = new QComboBox();
int i;
for(i=0; i < 4; i++){
QString *s = QString::string(currencyNames[i]);
box1->addItem(s);
}
hpp file:
#pragma once
#include string
.
.
.
static const int SIZE = 4;
std::string currencyNames[SIZE];
I keep getting a number of errors, I want an array containing the information above then loop through the array adding it to the QComboBox. Have no success. All relevant Qt headers included.

Besides the issues already stated in previous comments QComboBox::addItem method takes a reference to QString not a pointer.
Since you decided to use Qt framework you can embrace its collections which allows better interoperability with various widgets. Hence, your example could be rewritten a bit simplier.
For example:
QStringList currencyNames{"gbp","usd","eur","aud"};
QComboBox *box = new QComboBox();
box->addItems(currencyNames);
Just remember to assign the box to some parent to make it handle the box destruction when appropriate.

Related

Qt QList does not append local Objects

I have a understanding-problem why following code does not store any QString-Objects into my QList
QMap<QString, QList<QString> >map;
map = QMap<QString, QList<QString> >();
map.insert("eins", QList<QString>());
QList<QString> listInMap = map["eins"];
listInMap.append("test1");
listInMap.append("test2");
QList<QString> copyOfListInMap = map.value("eins");
qDebug() << copyOfListInMap.count();
Output: 0
The reason is simple: copy on write, aka. implicit sharing
QList<QString> listInMap = map["eins"];
At this point, you have not yet got a hard copy, only a "reference". That is not fair in the standard C++ sense, but imagine it as a "shallow copy". However, when you start appending in here, the list will copied and the original will left empty. It is because QList is implemented the way that is CoW (copy-on-write).
listInMap.append("test1");
listInMap.append("test2");
On a side note, you may wish to take a look at QStringList. While it inherits QList, it also has some additional convenience methods.
Now, you may be asking: How am I supposed to fill my map in, then?.
Multi map
I would personally suggest to use QMultiMap or at least QMap with insertMulti.
main.cpp
#include <QMap>
#include <QDebug>
#include <QString>
int main()
{
QMultiMap<QString, QString> map;
map.insert("eins", "test1");
map.insert("eins", "test2");
qDebug() << map.count();
return 0;
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
2
Single map
If you stick to the current approach, I would suggest to either append the value into a new QStringList with which you will overwrite the value, or hold a reference to the exact same list.
Having said that, in your case, it looks a bit overkill to even consider an external storage for insertion. You ought to do that right away in my humble opinion.
main.cpp
#include <QMap>
#include <QDebug>
#include <QString>
int main()
{
QMap<QString, QStringList> map;
map.insert("eins", QStringList{"test1", "test2"});
qDebug() << map.value("eins").count();
return 0;
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
2
According to the documentation your sample should be changed as follow:
QMap<QString, QList<QString> >map;
QList<QString> & listInMap = map["eins"]; // use reference here
listInMap.append("test1");
listInMap.append("test2");
QList<QString> copyOfListInMap = map.value("eins");
qDebug() << copyOfListInMap.count();

How to reference a form and change properties (height and width) from a function in Qt

I'm starting with Qt trying to migrate from VB6. And now I'm trying to change the size of a window (UI form) from a function, so before doing that in the action that opens the form I do this:
void F::on_actionCte_triggered()
{
Frm_ABM_Ctes *W = new Frm_ABM_Ctes(uF->mdiArea);
W->setAttribute(Qt::WA_DeleteOnClose);
W->setWindowState(Qt::WindowMaximized);
W->showNormal();
int Hi = (this->height()/3) - (W->height()/3);
int Wi = (this->width()/3) - (W->width()/3);
W->setGeometry(Wi,Hi,W->width(),W->height());
}
That works fine, the idea is that if I gonna do a lot of forms I want to call a function where it changes the geometry property of the child form. Like: Function(Parent,child) and then use Parent and Child as dynamic objects in my function (as I do in visual basic or VS)
So I did this:
void F::on_actionCte_triggered()
{
Frm_ABM_Ctes *W = new Frm_ABM_Ctes(uF->mdiArea);
W->setAttribute(Qt::WA_DeleteOnClose);
W->setWindowState(Qt::WindowMaximized);
W->showNormal();
FormS(This,W)
}
Where FormS is in a *.h file (which of course I include) and goes like this:
void FormS(QMainWindow Par, QMdiSubWindow Chi)
{
int Hi = (Par.height()/3) - (Chi.height()/3);
int Wi = (Par.width()/3) - (Chi.width()/3);
Chi.setGeometry(Wi,Hi,Chi.width(),Chi.height());
}
and it gives
error: could not convert 'this' from 'F* const' to 'QMainWindow'
FormS(this,W);
^
I don't know which is the best way to approach to my problem. Is there a way to create a public pointer and change any property of that form, or something like that?
Thanks for taking the time to read my problem any help will be appreciated.
First of all, you are trying to pass pointers into this method, so you'll need to adjust the method to take those pointers. Secondly, I'm not sure what F is (you haven't shown the declaration), but if it's a QMainWindow subclass this will work fine like so:
void FormS(QMainWindow *Par, QMdiSubWindow *Chi)
{
int Hi = (Par->height()/3) - (Chi->height()/3);
int Wi = (Par->width()/3) - (Chi->width()/3);
Chi->setGeometry(Wi, Hi, Chi->width(), Chi->height());
}

Random segmentation faults?

Note, problem has been identified, refer to second section for current detail and the third section for the most likely reason and a question on how to remedy it
I'm writing a program in Qt and I stopped a couple days ago at a segmentation fault problem. It seemed to complain about memory not being allocated. I searched around and couldn't figure out why there was an allocation problem and I took a break. Now, looking at it again, the segmentation fault is still there, but it's in a completely different, mostly unrelated function. What could be causing these random segmentation faults?
For some concreteness, in this case, I am currently getting a segmentation fault here:
Q_DECL_CONSTEXPR inline int QSize::height() const
{ return ht; }
I was getting it here before I commented out the lines (the last three lines)
qDebug() << QString("---SETTINGS DEBUG---")+QString("\r\n")<<
"netProcPage: "+netProcPage.url()+"\r\n" <<
"mapSize.width(): "+QString::number(mapSize.width())+"\r\n"<<
"mapSize.height(): "+QString::number(mapSize.height())+"\r\n"<<
"mapZoom: "+QString::number(mapZoom)+"\r\n"<<
"mappxSize.width(): "+QString::number(mappxSize.width())+"\r\n"<<
"mappxSize.height(): "+QString::number(mappxSize.height())+"\r\n"<<
"UserCoords[0]: "+QString::number(UserCoords[0])+"\r\n"<<
"UserCoords[1]: "+QString::number(UserCoords[1])+"\r\n"<<
"mapCoordOffsets[0]: "+QString::number(mapCoordOffsets[0])+"\r\n"<<
"mapCoordOffsets[1]: "+QString::number(mapCoordOffsets[1])+"\r\n"<<
"getWindowSize.width(): "+QString::number(getWindowSize.width())+"\r\n"<<
"getWindowSize.height(): "+QString::number(getWindowSize.height())+"\r\n"<<
"mappxOffsets[0]: "+QString::number(mappxOffsets[0])+"\r\n"<<
"mappxOffsets[1]: "+QString::number(mappxOffsets[1])+"\r\n"<<
QString("---END SETTINGS DEBUG---")+QString("\r\n");
Before then, without changing anything (just waiting a couple days and a couple restarts later), it was here:
mkeMap.genMap(QString("Map1"), tempmapSize, tempmapZoom, mapDisp->ui);
In the MainWindow class constructor complaining about tempmapSize, which is defined by:
QSize tempmapSize;
tempmapSize = settings->mapSize; //<--- The error might be coming from here, is there an alternative?
which is where the segmentation faults have been associated with. This is the settings class:
#include "settings.h"
Settings::Settings(QWidget *parent)
{
netProcPage = "http://localhost:81";
// Max image size is 32767x32767 pixels (divided by 4*mapZoom since 4 panes are used at mapZoom zoom)
// If max mapZoom is 20, max size of map is 409x409, or 408x408 to keep it even
mapSize.setWidth(250);
mapSize.setHeight(250);
mapZoom = 10;
mappxSize.setWidth(mapSize.width()*mapZoom);
mappxSize.setHeight(mapSize.height()*mapZoom);
//downloadMap(netProcPage,"getMap","Username","Password");
//makeMap("bingbong",mapSize,mapZoom);
UserCoords[0] = 0;
UserCoords[1] = 0;
mapCoordOffsets[0] = UserCoords[0] + .5 * mapSize.width();
mapCoordOffsets[1] = UserCoords[1] + .5 * mapSize.height();
//getWindowSize.setWidth(parent->width());
//getWindowSize.setHeight(parent->height());
getWindowSize.setWidth(500);
getWindowSize.setHeight(500);
mappxOffsets[0] = UserCoords[0]*mapZoom + .5 * getWindowSize.width() - .5 * mappxSize.width();
mappxOffsets[1] = UserCoords[1]*mapZoom + .5 * getWindowSize.height() - .5 * mappxSize.height();
}
void Settings::debug()
{
qDebug() << QString("---SETTINGS DEBUG---")+QString("\r\n")<<
"netProcPage: "+netProcPage.url()+"\r\n" <<
"mapSize.width(): "+QString::number(mapSize.width())+"\r\n"<<
"mapSize.height(): "+QString::number(mapSize.height())+"\r\n"<<
"mapZoom: "+QString::number(mapZoom)+"\r\n"<<
"mappxSize.width(): "+QString::number(mappxSize.width())+"\r\n"<<
"mappxSize.height(): "+QString::number(mappxSize.height())+"\r\n"<<
"UserCoords[0]: "+QString::number(UserCoords[0])+"\r\n"<<
"UserCoords[1]: "+QString::number(UserCoords[1])+"\r\n"<<
"mapCoordOffsets[0]: "+QString::number(mapCoordOffsets[0])+"\r\n"<<
"mapCoordOffsets[1]: "+QString::number(mapCoordOffsets[1])+"\r\n"<<
"getWindowSize.width(): "+QString::number(getWindowSize.width())+"\r\n"<<
"getWindowSize.height(): "+QString::number(getWindowSize.height())+"\r\n";//<<
//"mappxOffsets[0]: "+QString::number(mappxOffsets[0])+"\r\n"<<
//"mappxOffsets[1]: "+QString::number(mappxOffsets[1])+"\r\n"<<
//QString("---END SETTINGS DEBUG---")+QString("\r\n");
}
QSize* Settings::getmapSize()
{
return &mapSize;
}
int Settings::getmapZoom()
{
return mapZoom;
}
---
Here's the problem (identified)
I've refactored the code as suggested and I have pinpointed the exact problem, but I don't know how to fix it.
void makeMap::genMap(QString name, QPointF* inSize, int* zoom, Ui::MapDisp* ui)
{
QVector<QString> mapvector;
QPointF mapSize = *inSize; // <--- The problem is right here
...
}
The problem occurs when dereferencing the QPointF object found in an earlier instance of Settings, which was sent to genMap(...).
The call was done like this:
QPointF* tempmapSize;
tempmapSize = settings->getmapSize();
int* tempmapZoom = settings->getmapZoom();
mkeMap.genMap(QString("Map1"), tempmapSize, tempmapZoom, mapDisp->ui);
Wherever I moved the dereference (*Settings::inSize*, or *inSize), that's where the error occurred (in the debugger). Everything has been compiling fine.
When running the program, it crashes with this error:
Starting C:\program-debug.exe...
ASSERT failure in QVector<T>::operator[]: "index out of range", file ../../../../../Qt/5.2.0/mingw48_32/include/QtCore/qvector.h, line 369
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
C:\program-debug.exe exited with code 3
This reference to QVector<T> is referring to later in genMap,
void makeMap::genMap(QString name, QPointF* inSize, int* zoom, Ui::MapDisp* ui)
{
QVector<QString> mapvector;
QPointF mapSize = *inSize; //<---Here's the segmentation fault
/* Using this instead of the above works, as well as replacing zoom which causes another segmentation fault when dereferenced
QPointF mapSize;
mapSize.setX(250);
mapSize.setY(250);
int zoom0 = 10;
*/
QFile file(name+"_"+QString::number(mapSize.x())+"x"+QString::number(mapSize.y())+".rtsmap");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
mapvector.resize(mapSize.x() * mapSize.y());
for(int x = 0; x < mapSize.x(); x++){
for(int y = 0; y < mapSize.y(); y++){
uint decimalcolor = (((qSin(x)+1) + (qSin(y)+1))/4)>1?16777215:(((qSin(x)+1) + (qSin(y)+1))/4)*16777214;
QString hexadecimalcolor;
hexadecimalcolor.setNum(decimalcolor,16);
mapvector[index(x, y, mapSize)] = "#" + hexadecimalcolor;
//drawRect(x*10,y*10,10,10,"#"+hexadecimalcolor,zoom);
out << "#" << hexadecimalcolor+'\n';
}
}
file.close();
drawMap(mapvector,zoom0,ui,mapSize);
}
In Short
I think the problem is a dangling pointer. More specifically, when I pass the settings pointer to the class constructor, here:
MapCtrl::MapCtrl(QWidget *parent, Settings *settingsIn) :
QWidget(parent),
ui(new Ui::MapCtrl)
{
ui->setupUi(this);
mapDisp = new MapDisp(parent, settingsIn);
addMap();
settings = settingsIn;
}
The pointer settingsIn probably gets deleted at the end of the constructor with settings still pointing there, so later when I dereference a value from settings, it doesn't exist, causing a segmentation fault. So, the question is, how do I prevent the pointer called settingsIn from getting deleted at the end of the constructor?
requested code
Here's where the MapCtrl construtor MapCtrl::MapCtrl gets invoked and Settings is instantiated:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
wScr = new WelcomeScreen(this);
Settings *settings = new Settings(this);
mapCtrl = new MapCtrl(parent,settings);
...
}
solution (thanks to Kuba Ober for the guidance and the plethora of useful C++ knowledge)
In addition to checking for dangling pointers and fixing some possible causes, the final step was to change this:
MapCtrl::MapCtrl(QWidget *parent, Settings *settingsIn) :
QWidget(parent),
ui(new Ui::MapCtrl)
{
ui->setupUi(this);
mapDisp = new MapDisp(parent, settingsIn);
addMap();
qDebug() << "bingbong!!" << settingsIn->mapSize.x();
settings = settingsIn;
}
to this:
MapCtrl::MapCtrl(QWidget *parent, Settings *settingsIn) :
QWidget(parent),
ui(new Ui::MapCtrl)
{
ui->setupUi(this);
mapDisp = new MapDisp(parent, settingsIn);
qDebug() << "bingbong!!" << settingsIn->mapSize.x();
settings = settingsIn;
addMap();
}
settings was being set after a function that needed settings to be set.
In your entire codebase:
Get rid of places where you return Qt containers (QSize, QList, etc.) by pointer, and replace them with returning them by value.
Declare accessor methods const.
E.g. change Settings::getmapSize() to the below, idiomatic, code:
QSize Settings::getmapSize() const
{
return mapSize;
}
Use QPointF for coordinates, instead of naked arrays. Pass those into methods/functions by either value or const reference; the former may actually work a tad faster on modern hardware and compilers.
E.g. change the code in the constructor to be like this:
mapCoordOffsets = UserCoords + (toPoint(mapSize) * .5);
Where
static QPointF toPoint(const QSize & size) {
return QPointF(size.width(), size.height());
}
Get rid of the C-style output parameters, like in
void makeMap::genMap(..., QPointF* inSize, int* zoom, ...)
If you're returning something, simply return a structure that's called, say MapParams or somesuch:
MapParams makeMap::genMap(...);
If you're taking a structure and potentially modifying it, just modify it and return the modified one:
MapParams makeMap::genMap(..., MapParams params) {
...
params.size = ...;
params.zoom = ...;
...
return params;
}
My worry is that somewhere you're passing a bogus pointer or otherwise a pointer is obfuscating a lifetime issue. Naked pointers in modern C++ are highly suspect, and your code seems to use a lot of them for no good reason at all. Output parameters implemented with pointers are C-ism that has no place in modern C++.
Another common bug could be this: you have a Settings * settings member in the MainWindow class. Then you happily create a Settings * local variable in MainWindow constructor, but the MainWindow::settings member remains uninitialized. That's why you should always prepend member names with m_, so that they are harder to confuse with local variables. Ideally, you should use initializer lists to initialize members in a constructor.
When doing debugging, when you see an assert about out-of-bounds access, you need to debug its cause. A debugger should stop on such an assert, if not then you've got something misconfigured (what's your exact platform and toolset?). Whatever happens afterwards is meaningless if it was a write access, as memory has been overwritten, and you're chasing squirrels at this point.
Doing those things cuts down a whole bunch of errors that you've possibly made in your code. It may not fix your problem, but will get you on a good trajectory towards the solution.

Pull the strings from a managed Listbox to a class variable of type char*

This is confusing. I understand pointers but what is with tracking references?
The instructions are not very clear on what to do even on the wiki, not to mention I was never taught this in adv C++. So, How do I get the items in a listbox into one of my classes?
Also is can i get a brief rundown of tracking references for future reference?
My form has a Listbox called listbox2 with some data in it.
My class called "ManifistOBJ" has a method called "setFilename(char*)"
Now in other programs i can easily add objects to the "AddFilename" method but how do i do it for a tracking reference?
Sofar iv tried:
DMManifest newmanifest = DMManifest();
for(int i =1;i< listBox2->Items->Count;i++)
{
ManifistOBJ newobj = ManifistOBJ();
System::String^ temp = listBox2->Items[i]->ToString();
String temp1 = temp;//?
char* temp2 = temp1.c_str();
newobj.setFilename(temp2);
newmanifest.push_back(newobj);
}
With that ^ next to string I cant DE-reference it. and I have no idea how to.
I could make the method take a string^ but that would mess up my other programs that use that library.
#include <msclr/marshal_cppstd.h>
System::String^ temp = listBox2->Items[i]->ToString();
std::string temp1 = msclr::interop::marshal_as< std::string >( temp );
C++/CLI Converting from System::String^ to std::string

How to use VARIANT* with dynamicCall?

I'm trying to use a COM object and i'm having problem with the parameter type VARIANT*. I can use the functions of the COM object just fine, except when they have a parameter of this type.
The doc generated by generateDocumentation is :
QVariantList params = ...
object->dynamicCall("GetRanges(int,int,int&, QVariant&)", params);
According to the doc provided with the COM object, the parameters should be of type LONG, LONG, LONG* and VARIANT*, and it is precised that the VARIANT* is a pointer to a VARIANT containing an array of BSTR.
I should normally be able to retrieve the third and fourth parameter (of type LONG* and VARIANT*), and their values are not used by the function.
Here is my code (a and b are int previously initialized):
QStringList sl;
QVariantList params;
int i = -1;
params << QVariant (a);
params << QVariant (b);
params << QVariant (i);
params << QVariant (sl);
comobject->dynamicCall("GetRanges(int,int,int&,QVariant&)",params);
sl = params[3].toStringList();
i = param[2].toInt();
Now with that code, all i get is an error QAxBase: Error calling IDispatch member GetRanges: Unknown error, which is not very helpful.
I tried to change some things and I managed to progress (sort of) by using this code :
QStringList sl;
QVariant v = qVariantFromValue(sl);
QVariantList params;
int i = -1;
params << QVariant (a);
params << QVariant (b);
params << QVariant (i);
params << qVariantFromValue((void*)&v);
comobject->dynamicCall("GetRanges(int,int,int&,QVariant&)",params);
sl = params[3].toStringList();
i = param[2].toInt();
It gets rid of the error, and the value of i is correct at the end, but sl is still empty. And I know it should not be, because I have a sample demo in C# that works correctly.
So if anyone has an idea on how to make it works...
Otherwise I looked around a bit and saw that it was also possible to query the interface ans use it directly, but I didn't understand much, and I'm not sure it will solve my problems.
I'm on a Windows7 64 bits platform, and I'm using msvc2012 as compiler. I'm using Qt 5.1.0 right now, but it didn't work in the 5.0.2 either.
I guess you really can't do it with dynamicCall.
I finally found how to do it. It was easier than I'd thought. With the installation of Qt comes a tool called dumpcpp. Its full path for me was C:\Qt\Qt5.1.0x86\5.1.0\msvc2012\bin\dumpcpp.exe (obviously depends on settings). You can just add the bin folder to your path to make it easier to use.
Then I went into my project folder and executed this command :
dumpcpp -nometaobject {00062FFF-0000-0000-C000-000000000046} (the CLSID is just for the example, not the one I used)
It creates a header file, you can include it in the file where you're trying to use the COM Object.
In this file in my case there was two classes (IClassMeasurement and ClassMeasurement) in a namespace (MeasurementLib). Again, the names are not the real ones.
In your initial project file, you can call the desired function like this :
MeasurementLib::ClassMeasurement test; //Do not use IClassMeasurement, you only get write access violations
QVariant rangesVar;
int p1 = 0;
int p2 = 0;
int p3 = 0;
test.getRanges(p1,p2,p3,ranges);
QStringList ranges = ranges.toStringList();
Hopes that it helps someone !