I am trying to add a QPixmap to a QLabel taken from another QLabel but there is an error :
Here is the code
const QPixmap *tempPix = new QPixmap("");
tempPix = (label1->pixmap());
label2->setPixmap(tempPix); //error cannot convert from const QPixmap* to const QPixmap&
and if I do it like this:
const QPixmap tempPix("");
tempPix = (label1->pixmap()); //error cannot convert QPixmap and QPixmap*
label2->setPixmap(tempPix);
To copy data from a pointer object to an object you must use the *
QPixmap tempPix;
if(label1->pixmap()){
tempPix = *label1->pixmap();
label2->setPixmap(tempPix);
}
You can write it in a single line as follows:
label2->setPixmap(*label1->pixmap());
Note that * will convert the pointer returned by pixmap() to a reference. The difference between both is explained in this thread.
Note that in your first example, the constructed QPixmap in the first line is never used and a memory leak occurs. The second line changes the pointer value, not the data of the newly constructed object.
Related
Disclaimer: I am total newbie to Qt.
Let's assume we have a byte array returned from a function innerFunc that is later used in another function outerFunc.
QByteArray innerFunc(){
QProcess ls;
ls.start("ls", QStringList() << "-1");
return ls.readAll();
}
void outerFunc(){
QByteArray gotcha = innerFunc();
.
.
.
}
In vanilla c++ I would expect readAll function to return a pointer that needs to be deleted later. In Qt this function returns an instance of the QByteArray class so I guess it shouldn't be accessed outside of the innerFunc's scope.
If so, how should I properly transfer the data to an outer function? Should it copied to QByteArray *tmp = new QByteArray or is it unnecessary?
The code you have looks fine. QByteArray is like std::vector<uint8_t> or std::string and not like a pointer. It manages its own memory. It's fine to return it from a function or pass it to a function by value. The compiler will take care of copying and/or moving the data from one object to another as appropriate, using the contructors/operators defined by the QByteArray class.
QByteArray header file
QByteArray documentation
I try to present text with the following code:
void Text::display(SDL_Renderer *renderer, int x, int y) {
// pos is an SDL_Rect and font is a TTF_Font
pos.x = pos.w = x;
pos.y = pos.h = y;
SDL_Surface *surface = TTF_RenderText_Solid(font, text.c_str(), color);
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_QueryTexture(texture, NULL, NULL, &pos.w, &pos.h);
SDL_RenderCopy(renderer, texture, NULL, &pos);
SDL_FreeSurface(surface);
SDL_DestroyTexture(texture);
}
In my Text class. At first I had an uninitialized SDL_Color color in my Text::display() method which let me present a text on the screen. (renderer is passed from main + coordinates x,y). But I decided to make my SDL_Color color a private variable in the class Text instead. And what is weird to me is that as a private variable the text was flickering once I presented it, but if I set it as a public variable or placed it in the method the text was not flickering. Or if I initialized it as a private variable (SDL_Color color = {255, 255, 255}).
My question is if there was only pure luck that it worked when color was uninitialized as a public or method variable or if they are treated differently? When I initialized color in the constructor it was also flickering if color was private.
My main method:
void fpsCap(Uint32 starting_tick) {
if ((1000 / fps) > SDL_GetTicks() - starting_tick) {
SDL_Delay(1000 / fps - (SDL_GetTicks() - starting_tick));
}
}
int main(int argv, char** args) {
// Create renderer, window, etc
while (true) {
SDL_RenderClear(renderer);
Text *txt = new Text("hello");
txt->display(gui->getRenderer(), 0, 0);
SDL_RenderPresent(renderer);
}
}
The value of the private member is not initialized, and so it gets random/garbage value. As you allocate new Text instance for every frame. You allocate on heap (every time in a new place), so it is sort of guaranteed to actually be garbage.
Why it didn't flicker in other cases?
Public member: my guess is that you also made it static? Static variables are zero-initialized (contrary to member variables).
Local variable: local variables are not zeroed and are considered to contain garbage, but as they are stack-allocated, they are likely to get identical piece of garbage every single time in the given place.
Private member assigned in the constructor: that is unexpected. Are you sure that it was the same constructor that is actually used? And that it was the same variable? Perhaps some name shadowing prevented the value from actually landing where our should?
Tangential:
You leak a Text instance every loop. You should delete every object created with new, or better, avoid using new altogether. Use unique_ptr/make_unique instead, or just local variables (much better in this case).
EDIT to answer questions about new:
In modern C++ you almost never need to use new.
If you have an object that is used only during the execution of the function, the natural thing to do is to keep it directly (i.e. not through a pointer), in this case defining the variable as
Text txt("hello");
This is a similar idiom to Java's Text txt = new Text("hello");, but the result variable is an instance itself, and not a reference to it.
If you want to create an instance that you immediately pass as an argument of type Text or const Text&, you can create it as temporary like SomeFunction(Text("hello")) (note the lack of new, it's just the class name).
If you need heap allocation, smart pointers (std::unique_ptr and std::shared_ptr) created with std::make_unique and std::make_shared are
strongly preferred, as they guard from many common pitfalls such as memory leaks and dangling pointers, at least as long as you keep hold of the smart pointer itself. std::shared_ptr is probably closest thing standard C++ has to Java reference, although it's not garbage collected, so if you make a cycle of them, they won't be ever freed.
You could replace your Text *txt = new Text("hello"); with
auto txt = std::make_unique<Text>("hello");
to get the same behavior, but with the Text getting destroyed and deallocated at the end of the block.
I have the following code, which initializes a label to match an object's id.
for (int i = 0; i < inputVal; ++i)
{
QLabel *newLabel = new QLabel(p0[i]->id, page);
connect(p0, &Npc::setID, [&]
{ newLabel->text() = p0[i]->id; });
layout->addWidget(newLabel);
}
I'm trying to use the above connect to refresh the value of the label any time I change the value of the object's id. However, this doesn't work due to the label going out of scope and its value becoming inaccessible. Is there any way to access the label's value without declaring it outside of this scope?
This also hinges on the slot executing after the signal function does, which I would assume is the case. If it's not, is there any other way to update dynamic labels as object values change?
You can change your code as follows:
for (int i = 0; i < inputVal; ++i)
{
auto *obj = p0[i];
QLabel *newLabel = new QLabel(obj->id, page);
connect(obj, &Npc::setID, [obj, newLabel]
{ newLabel->setText(obj->id); });
layout->addWidget(newLabel);
}
Explanation: even though the pointer newLabel does indeed go out of scope after the loop iteration is finished, the actual QLabel it points to does not - it is created on the heap so it won't be deleted until something deletes it - in your case the layout would take care of it. So you can capture newLabel pointer by value (the address it points to would just be copied into the lambda) as well as the pointer to your object. You'd also need to use proper setText setter method of QLabel to assign new text to it; text method is a getter, it returns a copy of the text stored within the label, not a reference to it.
I want to extract a QIcon I've stored in one of a QTreeWidget's columns, as Qt::DecorationRole.
QTreeWidgetItem *item = ui->treeWidget->topLevelItem(index);
const QIcon &icon = item->data(0, Qt::DecorationRole)._howToConvert_();
However, I can only get the data as QVariant, and I could not find a function to convert from a QVariant to QIcon. Is it possible to do it?
OK, found the answer in the docs for QVariant upon further inspection.
This works:
QImage image = variant.value<QImage>();
I find the solution as follows:
QImage name_image = table_store_multi_model_->item(i_row,0)->data(Qt::DecorationRole).value().toImage();
Generally, we read data with data(), but here need a parameter "Qt::DecorationRole";
I have a C++ static class with a method that creates an object. I would like to retrieve the object created by this method in a different function so that this new function takes ownership of the object. This is the code I have so far:
MessageBoxes.h
class MessageBoxes {
public:
static int info(const QString& message, const QString& title = _("Information"), QMessageBox::StandardButtons buttons = QMessageBox::Ok);
static int confirmation(const QString& message, const QString& title = _("Confirmation"), QMessageBox::StandardButtons buttons = QMessageBox::Ok | QMessageBox::Cancel);
static int error(const QString& message, const QString& title = _("Error"), QMessageBox::StandardButtons buttons = QMessageBox::Ok);
private:
static QMessageBox& createMessageBox(const QString& message, const QString& title = "", QMessageBox::StandardButtons buttons = QMessageBox::Ok);
};
MessageBoxes.cpp
QMessageBox& MessageBoxes::createMessageBox(const QString& message, const QString& title, QMessageBox::StandardButtons buttons) {
QMessageBox msgBox;
msgBox.setWindowTitle(title);
msgBox.setText(message);
msgBox.setStandardButtons(buttons);
return msgBox;
}
int MessageBoxes::confirmation(const QString& message, const QString& title, QMessageBox::StandardButtons buttons) {
QMessageBox m = createMessageBox(message, title, buttons);
return m.exec();
}
The problem is that at the line QMessageBox m = createMessageBox(message, title, buttons), the compiler tells me that the copy constructor of QMessageBox is disabled. This is fine, however I do not want to make a copy, I want to get the actual object that was created in createMessageBox. I declared the return type of createMessageBox as QMessageBox& assuming that it would return the reference but it doesn't seem to work that way. Any idea how I can do that?
0) We don't do this "static class" thing in C++. Those are hacks to deal with the fact that Java and C# force you to put all your code into classes. C++ does not do that, so we shouldn't hack around a limitation that doesn't exist. Classes are not storage places for code; they exist to define a data type. What you're really trying to do is organize the code by grouping it under a common name; we do that with a namespace.
1) You may not return a reference to a local variable. References are for returning already-existing things.
2) You don't want to return a reference, because the purpose of createMessageBox is to create a message box. You return a value: the message box that was created.
3) When you write
Foo bar = something();
the result from something() is copied, even if something() did happen to return a reference to an already-existing thing. This is because the type of bar is Foo, and not Foo&. bar must hold its own Foo; it cannot refer to one, because it isn't a reference. And since the Foo returned by something() is a value in its own right, with its own location in memory, we can't just cause it to "be" bar; the program must make a copy.
To refer to the result from the function, you would write Foo& bar = something();. This will extend the lifetime of the returned object (which ordinarily would go out of scope right away), so there is no problem with referring to a temporary.
4) However, optimizing compilers are smart, and this is unlikely to gain you anything. If you just return a value and assign by value, chances are good the copy will not actually happen (although the Standard says in effect that your code must be prepared for that possibility).
5) Dynamic allocation is, honestly, a really bad idea here. If you must do it, at least use some kind of smart-pointer wrapper. Although, when your copy constructor is disabled, sometimes you're stuck with this sort of thing. :/
Your variable msgBox in the function createMessageBox is scoped to the function i.e. when you return from createMessageBox, msgBox is destroyed (taken off the stack) so you cannot have a reference to it. If the semantics are for the caller to take ownership of the variable, returning a reference is not the best way to convey it.
Firstly, you need to allocate msgBox dynamically:
QMessageBox* msgBox = new QMessageBox;
msgBox->setWindowTitle(title);
msgBox->setText(message);
msgBox->setStandardButtons(buttons);
Then, you need to return a pointer to the variable:
QMessageBox* MessageBoxes::createMessageBox(const QString& message, const QString&, QMessageBox::StandardButtons buttons) {
...
return msgBox;
}
Even this does not really tell the caller that they are taking ownership of the variable though. Since it is only a private method this might not matter too much but you should document when the caller is supposed to take ownership. Even better, you could use smart pointers to eliminate the need for such documentation :)
If you want to return a messageBox from createMessageBox, you should allocate it from the heap
QMessageBox *MessageBoxes::createMessageBox(const QString& message, const QString& title, QMessageBox::StandardButtons buttons) {
QMessageBox *pMsgBox = new QMessageBox();
pMsgBox->setWindowTitle(title);
pMsgBox->setText(message);
pMsgBox->setStandardButtons(buttons);
return pMsgBox;
}
This returns a pointer to the messageBox. If you fail to delete the pointer, it will leak memory.
The local you want to return the reference to, ceases to exist when your function returns. Even if you took the address of it &msgBox and returned that, you would be destroying the stack when you tried to use it. The only way for the MessageBox to continue to exist after your function returns is to create it using new.
You cannot return reference of a local variable, because local variable doesn't exist after the function returns, but the calling code might still use the reference to the object which doesn't exist anymore.
And since the copy-constructor is disable for QMessageBox, you cannot return it by value also.
You've to return it a pointer to a dynamically created object as:
QMessageBox * MessageBoxes::createMessageBox(const QString& message, const QString& title, QMessageBox::StandardButtons buttons) {
QMessageBox *pMsgBox = new QMessageBox();
pMsgBox->setWindowTitle(title);
pMsgBox->setText(message);
pMsgBox->setStandardButtons(buttons);
return pMsgBox;
}
Calling code:
QMessageBox *qMBox = createMessageBox(X, Y, Z);
//working with qMBox
delete qMBox; //must deallocate the memory when you don't need it anymore!
I would like to retrieve the object created by this method in a different function so that this new function takes ownership of the object.
Transferring ownership is done via std::unique_ptr<T> in C++0x:
#include <memory>
std::unique_ptr<QMessageBox> MessageBoxes::createMessageBox
(const QString& message, const QString& title, QMessageBox::StandardButtons buttons)
{
std::unique_ptr<QMessageBox> msgBox(new QMessageBox);
msgBox->setWindowTitle(title);
msgBox->setText(message);
msgBox->setStandardButtons(buttons);
return msgBox;
}
auto m = createMessageBox(message, title, buttons);
Note that no manual delete is necessary, the smart pointer already takes care of that.
In C++03, you can use the to-be-deprecated std::auto_ptr<T> instead.