Get Index of Qpushbutton on 2D Array Qpushbutton

Get index of QPushButton on 2D array QPushButton

The example looks like this:

screenshot

Qt 4/5 Using Object Names

You can give your buttons unique object names. The names should ideally be valid C++ identifiers.

// https://github.com/KubaO/stackoverflown/tree/master/questions/button-grid-22641306
#include <QtGui>
#if QT_VERSION_MAJOR >= 5
#include <QtWidgets>
#endif

struct Display : QLabel {
Q_SLOT void onClicked() {
auto const elements = sender()->objectName().split('_');
auto const i = elements.at(1).toInt();
auto const j = elements.at(2).toInt();
setText(QString{"(%1,%2)"}.arg(i).arg(j));
}
Q_OBJECT
};

int main(int argc, char *argv[])
{
QApplication a{argc, argv};
QWidget window;
QGridLayout layout{&window};
QVarLengthArray<QPushButton, 12> buttons(12);
Display display;

const int rows = 4, columns = 3;
for (int i = 0; i < rows; ++ i)
for (int j = 0; j < columns; ++j) {
auto & button = buttons[i*columns+j];
button.setText(QString{"(%1,%2)"}.arg(i).arg(j));
button.setObjectName(QString{"buton_%1_%2"}.arg(i).arg(j));
layout.addWidget(&button, i, j);
display.connect(&button, SIGNAL(clicked()), SLOT(onClicked()));
}
layout.addWidget(&display, rows, 0, 1, columns);

window.show();
return a.exec();
}
#include "main.moc"

Qt 5 - Using Lambdas

In Qt 5 and C++11, you should use functors to generate custom slot for each button, on the fly. For example:

// https://github.com/KubaO/stackoverflown/tree/master/questions/button-grid-22641306
#include <QtWidgets>

int main(int argc, char *argv[])
{
QApplication a{argc, argv};
QWidget window;
QGridLayout layout{&window};
QVarLengthArray<QPushButton, 12> buttons(12);
QLabel display;

const int rows = 4, columns = 3;
for (int i = 0; i < rows; ++ i)
for (int j = 0; j < columns; ++j) {
auto text = QStringLiteral("(%1,%2)").arg(i).arg(j);
auto & button = buttons[i*columns+j];
button.setText(text);
layout.addWidget(&button, i, j);
QObject::connect(&button, &QPushButton::clicked, [&display, text] {
display.setText(text);
});
}
layout.addWidget(&display, rows, 0, 1, columns);

window.show();
return a.exec();
}

Qt 4/5 - Using QSignalMapper

QSignalMapper is pretty much designed for what you want. It lets you map a QObject* to "something else", like a string. For example:

#include <QtGui>
#if QT_VERSION_MAJOR >= 5
#include <QtWidgets>
#endif

int main(int argc, char *argv[])
{
QApplication a{argc, argv};
QSignalMapper mapper;
QWidget window;
QGridLayout layout{&window};
QVarLengthArray<QPushButton, 12> buttons(12);
QLabel display;

const int rows = 4, columns = 3;
for (int i = 0; i < rows; ++ i)
for (int j = 0; j < columns; ++j) {
auto text = QString{"(%1,%2)"}.arg(i).arg(j);
auto & button = buttons[i*columns+j];
button.setText(text);
layout.addWidget(&button, i, j);
mapper.connect(&button, SIGNAL(clicked()), SLOT(map()));
mapper.setMapping(&button, text);
}
display.connect(&mapper, SIGNAL(mapped(QString)), SLOT(setText(QString)));
layout.addWidget(&display, rows, 0, 1, columns);

window.show();
return a.exec();
}

Qt 4/5 - Using the Property System

You can leverage the fact that a QWidget is a QObject. QObjects have a property system, so you can set each button's index as a property, and then retrieve it in the slot connected to the clicked() signal. For example:

#include <QtGui>
#if QT_VERSION_MAJOR >= 5
#include <QtWidgets>
#endif

const char kIndex[] = "index";
struct Display : QLabel {
Q_SLOT void onClicked() {
setText(sender()->property(kIndex).toString());
}
Q_OBJECT
};

int main(int argc, char *argv[])
{
QApplication a{argc, argv};
QWidget window;
QGridLayout layout{&window};
QVarLengthArray<QPushButton, 12> buttons(12);
Display display;

const int rows = 4, columns = 3;
for (int i = 0; i < rows; ++ i)
for (int j = 0; j < columns; ++j) {
auto index = QString{"(%1,%2)"}.arg(i).arg(j);
auto & button = buttons[i*columns+j];
button.setText(index);
button.setProperty(kIndex, index);
layout.addWidget(&button, i, j);
display.connect(&button, SIGNAL(clicked()), SLOT(onClicked()));
}
layout.addWidget(&display, rows, 0, 1, columns);

window.show();
return a.exec();
}
#include "main.moc"

qt how to connect 2D array of QPushButton and return the location

The answer you are linking is very complete and useful, I think you should stick with that one. Any suggestion about those methods would be just rewriting the original answer. Maybe you can ask something more specific about what you can't understand of those options.

Another solution, not cited in that answer, would be implementing a class extending QPushButton, intercept the clicked() signal and re-emit it with the data you want. The same thing can be obtained with lambda functions in Qt5 and C++11: have a look at this: qt-custom-qpushbutton-clicked-signal the two answers to this questions explain how to do this.

Processing signals from a dynamic button array

I would connect the buttons so that they all send a signal to the same slot.

I did not test this code. It is just an attempt for a proof of concept

class ButtonTable : public QWidget 
{
Q_OBJECT

public:
ButtonTable()
void createButtons();

private:
int height;
int width;
QVector<Button*> buttons

private slots:
btnClicked();
};

void ButtonTable::createButtons() {
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; j++) {
Button* btn = new Button(this);
btn.row = i;
btn.col = j;
connect(button, SIGNAL(clicked()), this, SLOT(btnClicked()));
buttons.push_back(btn);
}
}
}

void ButtonTable::btnClicked()
{
Button *btn = qobject_cast<Button *>(sender());
//Do something with button

}

class Button : public QToolButton
{
Q_OBJECT

public:
explicit Button(QWidget *parent = 0);
int row;
int col;
};

So there are many buttons but each clicked() button goes to one single slot. You can find out what button was pressed with QObject::sender(), and because they are custom buttons that inherit from QToolButton, you can store extra information you need inside that class.

Keep in mind you will also have to do the layout of the buttons programmatically because of the dynamic size.

Qt/C++ detect QPushButton hovered to playing sound

You can use event filters to detect hovering on a widget. Read everything necessary on the event system of Qt here.

Here a working example that plays a sound from a resource file (read everything you need about the Qt resource system here), changes the background of a label and prints to screen (I had these two options for debugging):

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMediaPlayer>

namespace Ui
{
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget* parent = nullptr);
~MainWindow();

virtual bool eventFilter(QObject* watched, QEvent* event);

private:
Ui::MainWindow* ui;
QMediaPlayer* player_ = nullptr;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>
#include <QEvent>
#include <QMediaPlaylist>
#include <QUrl>

MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
Q_INIT_RESOURCE(qt_resources);
ui->setupUi(this);
ui->pushButton->installEventFilter(this);
ui->label->setStyleSheet("background-color: red");
}

MainWindow::~MainWindow()
{
delete ui;
}

bool MainWindow::eventFilter(QObject* watched, QEvent* event)
{
if (watched == ui->pushButton && event->type() == QEvent::HoverEnter)
{
qDebug() << "Start hover";
ui->label->setStyleSheet("background-color: green");
if (!player_)
{
QMediaPlaylist* playlist = new QMediaPlaylist();
playlist->addMedia(QUrl("qrc:/push_button.mp3"));
playlist->setPlaybackMode(QMediaPlaylist::Loop);

player_ = new QMediaPlayer(this);
player_->setPlaylist(playlist);
player_->setVolume(50);
player_->play();
}
}
else if (watched == ui->pushButton && event->type() == QEvent::HoverLeave)
{
qDebug() << "End hover";
ui->label->setStyleSheet("background-color: red");
if (player_)
{
player_->stop();
player_->deleteLater();
player_ = nullptr;
}
}
return QMainWindow::eventFilter(watched, event);
}

main

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char** argv)
{
QApplication app(argc, argv);
MainWindow* mw = new MainWindow;
mw->show();
return app.exec();
}

You can download the working project (tested on Ubuntu 18.04 with Qt 5.9.5) here.

How to determine which widget triggered the slot function?

You can use the QObject::sender() function to determine which object emitted the signal. This function is documented here.

QSignalMapper Usage; Multiple QPushButtons assigned to one signal

On_Clicked is a signal, thus you need to connect a slot to it. Or just change On_clicked into slot and connect signal mapped(int) to it (use SLOT keyword then).

And notice that On_Clicked function you defined is not a class method which you would need.

Paint QPushButton with QLinearGradient

Without a success I've tried it with QPalette and done it successfully using setStyleSheet:

QPushButton* button = new QPushButton();
QString linearGradient = QString("qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));");

button->setStyleSheet(QString("background-color: %1").arg(linearGradient));

Also, we can use QString::arg(...) to set different colors and points for the gradient.

Hope this help you and excuse me for a stupid comment earlier )



Related Topics



Leave a reply



Submit