How to iterate through every QSpinBox in QGridLayout - c++

I have the following problem. I'm using Qt in the newest version 5.2 and in my code I have 11QSpinBox. Every in QGridLayout. I want to iterate through every QSpinBox in this layout and set value that I read from file. When I'm using:
ui.QSpinBox->setValue()
is everything ok, but the code looks too long.
I tried using:
static_cast<QSpinBox*>(ui.gridLayout->itemAtPosition(1,1)->widget())->setValue(100);
but I get exception Access violation and MS VS2010 show me this function in qatomic_mscv.h:
inline bool QAtomicOpsBySize<4>::deref(long &_q_value) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_DECREMENT(&_q_value) != 0;
}
So i thought about not using pointer to QSpinBox but an object:
static_cast<QSpinBox>(ui.gridLayout->itemAtPosition(1,1)->widget()).setValue(100);
but it didn't change the value. Any exception didn't occur.
OK, I used even dynamic_cast with pointer type and I got again access Violation but this time VS2010
point me to qscopedpointer.h:
inline T *data() const
{
return d;
}
It happens for qobject_cast too.
I'm sure that position point to QSpinBox. What I'm doing wrong?

Consider using qFindChildren instead:
QList<QSpinBox*> spinBoxen = ui.findChildren<QSpinBox*>();
Q_FOREACH(QSpinBox *spinBox, spinBoxen) {
// do something to do the spinBox
}

Related

I get an uninitialized object from a pointer

So i have some troubles getting pointers to work with SFML shapes. I'm not sure if it has something to do with SFML or if I'm doing anything wrong.
In Draw() x(a ControlWindow) does not contain valid values, it only shows "???" as shown here. However the m_controls(map) contains the correct values for the control object.
I'm quite new to C++ so any help would be greatly appreciated.
Exception
Exception thrown at 0x60B26EE5 (sfml-graphics-2.dll) in OokiiUI.exe: 0xC0000005: Access violation reading location 0x00000000.
Main
vector<WindowControl> windowControls;
void Draw ();
int main ()
{
RectangleShape rect(Vector2f(120,120));
WindowControl windowControl(nullptr,0);
Control testControl(&windowControl,1);
testControl.SetShape(&rect);
windowControl.AddControl(testControl);
windowControls.push_back(windowControl);
return 0;
}
WindowControl
class WindowControl : Control
{
public:
WindowControl ( WindowControl * windowControl, uint64_t uint64 )
: Control ( windowControl, uint64 )
{
}
void AddControl(Control control)
{
m_controls.insert_or_assign(control.GetId(), control);
m_controlPtrs.push_back(&control);
}
vector<Control*>* GetControls()
{
return &m_controlPtrs;
}
private:
map<uint64_t, Control> m_controls;
vector<Control*> m_controlPtrs;
};
Draw
for (auto x : windowControls)
{
vector<Control*> *controlPtrs = x.GetControls();
window->draw(x.GetControl(0)->GetShape());
}
There is a problem here:
void AddControl(Control control)
{
m_controls.insert_or_assign(control.GetId(), control);
m_controlPtrs.push_back(&control);
}
You add the address of the parameter control which is destroyed when the function ends. It looks like you want to add the address of the copy that you add to your map like this:
void AddControl(Control control)
{
m_controls.insert_or_assign(control.GetId(), control);
// don't use the parameter here, use the copy you put in the map
m_controlPtrs.push_back(&m_controls[control.GetId()]);
}
Although that is not ideal because if you send the same control twice, it will only appear once in the map (updated) but twice in the vector of pointers. You can use the returned pait from insert_or_update to fix that:
void AddControl(Control control)
{
auto [iter, was_inserted] = m_controls.insert_or_assign(control.GetId(), control);
// only add to vector if it was not in the map before
if(was_inserted)
m_controlPtrs.push_back(&iter->second);
}
A side note:
It is more idiomatic to return a reference in this situation rather than a pointer:
vector<Control*>& GetControls()
{
return m_controlPtrs;
}
This also breaks encapsulation so it may be worth thinking about how you can avoid accessing the internals of your objects so directly.
Your problem is that you are adding the pointer of a local variable into your m_controlPtrs:
void AddControl(Control control)
{
m_controlPtrs.push_back(&control);
}
Here you take a copy of Control, then add the address of that into your vector. The moment the function returns, your object goes out of scope and that memory is pointing to uninitialised garbage.
You probably want to update AddControl to take a Control&.
#ShadowRanger raises a good point in the comments: what I've mentioned may fix your issue, perhaps indefinitely, but your design still isn't terrific. Any time you have a Control which won't outlive m_controlPtrs you're going to encounter this same problem. Your code is small now, but this may eventually turn into a nightmare to fix. It's likely you should instead update m_controlPtrs to share (or take) ownership of the Control so this problem won't occur.
The easiest way out is to have m_controlPtrs declared as a std::vector<std::shared_ptr<Control>>, but it's something you should think about.

How to get data back from QVariant for a usertype?

I'm using a QVariant to store a pointer to my object in a QComboBox
void MainFrame::initContainerBox(QComboBox *oBox)
{
IDataContainer *idc = new CSVContainer();
QVariant v(QVariant::UserType, idc);
oBox->addItem(idc->getContainername(), v);
void *idc1 = v.data();
if(idc1 == idc)
printf("Test\n");
}
But how do I get the data back? When I use data() the pointer is different, so this doesn't seem to be correct. From gooogling I had the impression that I have to register a type for each class I want to use in a QVariant is that correct or can I retrieve the value without that?
After two days of googling and trying all kind of combinations I finally found out how to do this. Here is an example using a QComboBox putting an item and getting it back. IDataContainer * is an arbitrary class which is not related to Qt.
Q_DECLARE_METATYPE(IDataContainer *)
void MainFrame::initContainerBox(QComboBox *oBox)
{
IDataContainer *idc = new CSVContainer();
QVariant v;
v.setValue(idc);
oBox->addItem(idc->getContainername(), v);
QVariant v2 = oBox->itemData(oBox->currentIndex());
IDataContainer *idc1 = v2.value<IDataContainer *>();
if(idc1 == idc)
printf("Test\n");
}
So with my first approach of using value() I was on the right track, the only missing bits were how to set the value and using the macro Q_DECLARE_METATYPE(IDataContainer *).
Apparently using the constructor doesn't work, so one has to call setValue() instead. If somebody knows how to use the constructor it would be nice to show it.

QT - QTableView removeRow() crashing

This function should remove a row from my QStandardItemModel attached to a QTable View.
void ModManager::delete_Addin(int index)
{
QString addinId;
int i;
addinId = tableModel->item(index,0)->text();
for(i=0;i<modList->size();i++)
{
if(modList->at(i)->Id() == addinId)
{
delete modList->takeAt(i);
break;
}
}
tableModel->removeRow(index);
}
The strange thing is that the program crashes at the last instruction, tableModel->removeRow(index);
And its not going out of range because tableModel->item(index,0) is valid.
What could it be, then?
the code does not present relativity between modList and tableModel. tableModel->item(index,0) was valid before changing modList, while tableModel->rowAt(index) becomes invalid after modifying. There are a few possibilities:
Modifying modList affects tableModel, as #vahancho implies. This can be verified by commenting out the for loop or changing the order of lines. This can be lead by use modList as the real data of tableModel, for example, are you implementing a custom QTableModel by returning modList->at(i) as QTableModel::Data and returning modList->count() as QTableModel::rowCount()?
modList does not affect tableModel, but the item was referenced somewhere else. this cannot be tell from the code.

Problem with GtkTextBuffer , Confusing Runtime Error. Need Help?

I am using this code:
class editbook
{
GtkWidget* _nbook;
std::vector<GtkWidget*> _srcset; //and so on...
...........................................................................................
void editbook::add_page()
{
GtkWidget* tmp = gtk_source_view_new();
_srcset.push_back(tmp);
gtk_notebook_append_page(GTK_NOTEBOOK(_nbook),tmp,gtk_label_new("untitled"));
}
...........................................................................................
void editbook::set_text(const std::string& text)
{
int index = gtk_notebook_get_current_page(GTK_NOTEBOOK(_nbook));
GtkTextBuffer* tbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(_srcset[index]));
gtk_text_buffer_set_text(GTK_TEXT_BUFFER(tbuffer),text.c_str(),-1);
}
Compiles fine. But gives this weird runtime error:
Segementation Fault: return 139
I have traced down the problem to: gtk_text_view_get_buffer(GTK_TEXT_VIEW(_srcset[index]));
NOTE: I am using GtkSourceView instead of GtkTextView, but that may not be a problem because I am gettin the same error when I try GtkTextView.
NOTE: I am using Gtk 2x
NOTE: I am not sure whether to tag this question with C or C++. bec. Gtk+ is a C lib. But I am using C++. So I'll just tag both for now.
The problem in your code could be that the child widget added to GtkNotebook through gtk_notebook_append_page is not visible, try showing the child widget through gtk_widget_show call. Something on these lines :
void editbook::add_page()
{
GtkWidget* tmp = gtk_source_view_new();
_srcset.push_back(tmp);
gtk_widget_show(tmp); //Show the child widget to make it visible
gtk_notebook_append_page(GTK_NOTEBOOK(_nbook),tmp,gtk_label_new("untitled"));
}
When you use gtk_notebook_get_current_page if none of the child widget are visible then it returns -1, which I think might be happening in your case & as index is -1 when you use operator[] which doesn't check for bounds the program crashes. I strongly suggest you use vector::at instead of using operator[] so that you get std::out_of_range exception during run time to indicate the problem. You could use:
void editbook::set_text(const std::string& text)
{
int index = gtk_notebook_get_current_page(GTK_NOTEBOOK(_nbook));
GtkTextBuffer* tbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(_srcset.at(index)));
gtk_text_buffer_set_text(GTK_TEXT_BUFFER(tbuffer),text.c_str(),-1);
}
Hope this helps!

segfault when trying to access a string member of a class

I have a class Message that has a std::string as a data member, defined like this:
class Message
{
// Member Variables
private:
std::string text;
(...)
// Member Functions
public:
Message(const std::string& t)
: text(t) {}
std::string getText() const {return text;}
(...)
};
This class is used in a vector in another class, like this:
class Console
{
// Member Variables
private:
std::vector<Message> messageLog;
(...)
// Member Functions
public:
Console()
{
messageLog.push_back(Message("Hello World!"));
}
void draw() const;
};
In draw(), there's an iterator that calls getText(). When it does, the program segfaults. I've determined that text is valid inside the Message constructor. However, I can't tell if it's valid from inside Console. I'm assuming it is, but if I try to inspect indices of Console's messageLog, gdb tells me this:
(gdb) p messageLog[0]
One of the arguments you tried to pass to operator[] could not be converted to what
the function wants.
Anyone know what's going on?
EDIT: here's draw(). TCODConsole is part of a curses library I'm using, and so this function prints each message in Console to a part of the curses screen. TL and BR are Point member objects (two ints) that tell where on the screen to draw Console. I left out parts of Message and Console in the original question to hopefully make things clearer, but if you need me to post the entire classes then I can. They aren't too long.
void Console::draw() const
{
int x = TL.getX(), y = TL.getY();
int width = BR.getX() - TL.getX();
int height = BR.getY() - TL.getY();
// draw the Console frame
TCODConsole::root->printFrame(x, y, width, height, true);
// print the Console's messages
vector<Message>::const_iterator it;
for(it=messageLog.begin(); it<messageLog.begin()+height-1; ++it)
{
string message = "%c" + it->getText();
TCODConsole::setColorControl(TCOD_COLCTRL_1,
it->getForeColor(),
it->getBackColor());
y += TCODConsole::root->printRectEx(x, y, width, height,
TCOD_BKGND_NONE,
TCOD_LEFT,
message.c_str(),
TCOD_COLCTRL_1);
}
}
My guess is that by the point you use it->getText(), the iterator is NULL. Add a check it != messageLog.end() when you walk the array, and before calling it->getText().
Is it definitely std::vector messageLog and not std::vector<Message> messageLog? That seems a bit odd.
What does the height have to do with the vector's index? You have:
messageLog.begin()+height-1;
Why are you adding the screen coordinate to the iterator? That seems to be your problem and you're most likely overindexing and that's why you're getting a SIGSEGV.
What you probably want is to simply iterate over all the messages in the vector and display them at a particular location on the screen. I see what you're trying to do, but if you're trying to calculate the screen boundary using the iterator you're definitely going about it the wrong way. Try running a counter or get messageLog.size() and then recalculate the height with each iteration. As for the loop just do:
for(it=messageLog.begin(); it!=messageLog.end(); ++it)
It's probably because the scope of the Message object created in the Console method is just the Console method. So, if your program is trying to access this object in another method, like draw, you will get this segmentation fault, since this object is deleted after the execution.
Try this (just insert a new keyword):
Console()
{
messageLog.push_back(new Message("Hello World!"));
}
In this case, the object is not deleted after Console's end.
Just remember to delete the objects created when your program doesn't need them anymore.