QT retrieve custom widget from layout - c++

I have a scroll area with a layout that has 8 of the same custom widgets that have been added to it. This custom widget has a getter function that will return a value. My question is how to get back that original custom widget so I can call the getter function to retrieve the data it stores?
I have added the custom widget to the layout this way:
for (int var = 0; var < 9; ++var) {
calcRow *CalcWidget = new calcRow(this, &js, KeyList, SizeList);
connect(CalcWidget, &calcRow::testSignal, this, &MainWindow::getRowData);
ui->scrollArea_layout->layout()->addWidget(CalcWidget);
}
Where I am stuck:
void MainWindow::getRowData()
{
for (int i = 0;i < ui->scrollArea_layout->layout()->count() ;++i ) {
QWidget *row = ui->scrollArea_layout->layout()->itemAt(i)->widget();
if(row != NULL)
{
std::cout << row->"SOMETHING TO GET CALCROW WIDGET" <<std::endl;
}
}
}

Usually it's not the best structure for your code, any layout change might break your implementation. For example this solution will not work if you will have multiple calcRow widgets.
To make it better, you can pass required parameters which you want use inside getRowData as a parameters of testSignal signal.
Or just simplify it even more with lambda:
for (int var = 0; var < 9; ++var) {
calcRow* CalcWidget = new calcRow(this, &js, KeyList, SizeList);
connect(CalcWidget, &calcRow::testSignal, [CalcWidget]()
{
std::cout << CalcWidget->"SOMETHING TO GET CALCROW WIDGET" << std::endl;
});
ui->scrollArea_layout->layout()->addWidget(CalcWidget);
}

For anyone else that will find this in the future, the comments helped a bunch and I ended up using static_cast. My final code looks like this:
void MainWindow::getRowData()
{
for (int i = 0;i < ui->scrollArea_layout->layout()->count() ;++i ) {
QWidget *row = ui->scrollArea_layout->layout()->itemAt(i)->widget();
calcRow *rowConverted = static_cast<calcRow*>(row);
if(row != NULL)
{
std::cout << rowConverted ->getData() <<std::endl;
}
}
}

Related

Template deduction error binding QComboBox::currentIndexChanged to lambda [duplicate]

I want to get QString text from selected QComboBox. When I selected an index on a QComboBox, I want to get QString from the selected index, after I clicked the desired index on a QcomboBox.
I have researched about this,
Qt QCombobox currentIndexChanged signal
but have not found a way to solve it,
QVector<QComboBox*> cboxes;
for (int i =0; i< 40 ; i++)
{
QComboBox *box = new QComboBox();
cboxes.append(box);
}
for(int i = 0; i < 40; i++)
{
connect(cboxes[i], SIGNAL(currentIndexChanged(const QString &text)), this, SLOT(comboBoxAdjusted_Changed(QString)));
}
comboBoxAdjusted_Changed function
void DialogSettings::comboBoxAdjusted_Changed(QString text)
{
std::cout << text.toStdString() << endl;
}
I have Try, but everytime i change the combobox index, It isn't give output.
for (int i =0; i< 40 ; i++)
{
connect(cboxes[i], static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::currentIndexChanged),
[=](const QString &text){
std::cout << text.toStdString() << endl;
});
What should I do?
I see signal syntax is missing the function input argument.
Below are two valid signals for currentIndexChanged
void currentIndexChanged(int index)
void currentIndexChanged(const QString &text)
If you have to handle index try below for your case.
for(int i = 0; i < 40; i++)
{
connect(cboxes[i], static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),[=](int index){ /* YOUR CODE */ });
}

change labels by horizontal scrollbar

I have an horizontal scrollbar which change the value (number) of two labels when I scroll it.
Bul, I also want that when you scroll it, it changes the picture on a stacket widget.
one picture when the value goes to 0-40, other when it´s from 41-70 and the last from 71-100.
The only thing I have achive is change the image but one by one.
Anyone can help me? I´ve give you the code of this:
wave++;
if(wave==1)
{
ui->VolumeSWWave_5->setCurrentIndex(1);
}
if(wave>1)
{
wave=0;
ui->VolumeSWWave_5->setCurrentIndex(0);
}
{
return;
for (int i = 0; i < 10; ++i)
qDebug("%1", i);
}
if(wave<1)
{
wave=0;
ui->VolumeSWWave_5->setCurrentIndex(2);
}
{
return;
for (int i = 0; i > 10; ++i)
qDebug("%1", i);
}
The QAbstractSlider has a signal (the actionTriggered(int)) if you "catch" that signal then you can in an if else block decide what picture is getting displayed:
void MainWindow::on_horizontalScrollBar_sliderMoved(int position)
{
qDebug() << "position: " << position;
if (position <= 40)
{
qDebug() << "set at index 1";
}
else if (position > 40 && position <= 71)
{
qDebug() << "set at index 2";
}
else
{
qDebug() << "set at index 3";
}
}

QTableWidget to multiple files

I’ve got QTableWidget with data like this:
table.png
The table can contains only names from the QList:
QList<QString> shapes { "Triangle", "Circle", "Trapeze", "Square", "Rectangle", "Diamond" };
with random int values in the neighboring cell.
Table can contain all "shapes" or only a part of it (like in the example).
I try to create separate file for each shape form the table and write down corresponding int values to them.
To achieve this I wrote something like that:
QList<QTableWidgetItem *> ItemList
/.../
for(int i = 0; i < rows; ++i)
{
for(int i = 0; i<columns; ++i)
{
foreach(QString itm, shapes )
{
ItemList = ui->tableWidget->findItems(itm, Qt::MatchExactly);
QFile mFile(itm + ".txt");
if(mFile.open(QFile::ReadWrite))
{
for(int i = 0; i < ItemList.count(); ++i)
{
int rowNR = ItemList.at(i)->row();
int columnNR = ItemList.at(i)->column();
out << "Values = " << ui->tableWidget->item(rowNR, columnNR+1)->text() << endl;
}
}
}
mFile.flush();
mFile.close();
}
}
Files are created for every item from the QList – if the shape from the QList is not in the table, an empty file is created.
How to create files only on the basis of available names in the table?
You can write like this.
QList<QTableWidgetItem *> ItemList
/.../
for(QString str : Shapes){
ItemList = ui->tableWidget->findItems(itm, Qt::MatchExactly); // Get the matching list
if(ItemList.isEmpty(){
continue; // If shape does not exist in table skip the iteration
}
QFile mFile(str + ".txt");
if(!mFile.open(QFile::ReadWrite){
return; // This should not happen ; this is error
}
for(QTableWidgetItem *item : ItemList){
int row = item->row();
int col = item->column()+1; // since it is neighboring cell
QString Value = ui->tableWidget->item(row,col)->text();
mFile.write(Value.toUtf8()); // You can change the way in which values are written
}
mFile.flush();
mFile.close();
}

How to center a widget in QScrollArea?

Constructor:
ScrollArea::ScrollArea(...)
{
...
end = myItems.count();
for(int i=0; i<end; i++)
{
scrollItems.append(new ScrollItem(myItems.at(i), 0, width, i, this));
}
scrollArea->setWidget(this); //must be last for auto-scrolling to work
}
Member function:
void ScrollArea::updateSelection(int selection)
{
foreach(ScrollItem* item, scrollItems)
{
if(item->updateSelection(selection, 0))
{
scrollArea->ensureWidgetVisible(item);
}
}
}
After running ScrollArea::updateSelection, it looks like this:
I want it to look like this:
Google returns a mis-titled question (as far as I can tell: Place widget in center of QScrollArea) and a bunch of junk.
Still don't know why QScrollArea::ensureWidgetVisible doesn't work, even with explicit margins, but I found something that does:
void ScrollArea::updateSelection(int selection)
{
int item = -1;
int i = scrollItems.count();
while(i)
{
i--;
if(scrollItems.at(i)->updateSelection(selection, 0))
{
item = i;
}
}
if(item < 0)
{
return;
}
i = scrollItems.first()->height();
item *= i;
item += i / 2;
//item is now the position that should be centered
scrollArea->verticalScrollBar()->setValue(
item - (scrollArea->height() / 2)
);
}
So I'm basically brute-forcing what I want instead of having the library do it. (and fail)

Using delete on pointers in a a vector

I am a hobby coder who is learning by trying to make a text-RPG game on the console. I am just trying to think about how to design my code right now, and I'm getting stuck on how the items and inventory classes will work together. I have the inventory class defined like so:
class Inventory {
private:
vector<Item*> items;
public:
Inventory() {
items.resize(10);
for (int i = 0; i < 10; ++i) {
items[i] = nullptr;//so I can still display an empty inventory
}
};
~Inventory() {
for (int i = 0; i < 10; ++i) {
delete items[i];
}
}
void AddItem(Item* item) {
for (int i = 0; i < items.size(); ++i) {
if (items[i] == nullptr) {//if the slot is empty
items[i] = item;
break;
}
}
}
void Show() const {
for (int i = 0; i < items.size(); ++i) {
cout << "Slot " << i + 1 << ": ";
if (items[i] == nullptr) {
cout << "<Empty Slot>" << endl;
} else {
cout << "<" << items[i]->GetName() << ">" << endl;
}
}
}
};
Eventually I'm planning on having enemies dropping loot when they die, so I'll need to create items using new and then transfer them into the player's inventory. My question is, should I just learn about smart pointers and use them, or is the way I've called delete here okay or completely stupid? Or should I be thinking about this code structure differently? Thanks for answering, if you do! I really appreciate it.
The correct method would be to use iterators. Don't pass pointer of 'Item' in
void AddItem(Item* item) method.
You should create an iterator of 'Item' class and pass this iterator to "AddItem" method. Similarly create another method "RemoveItem" that returns an iterator of 'Item' that can be sent to Player's "CollectMoney" method.
If you don't want to use iterators, you can use "Item * item" as well but you have to call a method "RemoveItem" to get the reference of the "Item" so you can pass it to Player. Since the Items are not created inside the class, they should not be deleted in the class so remove the destructor.
PS use this constructor -> Inventory() {items.resize(10,nullptr);}