Get index of QPushButton on 2D array QPushButton
The example looks like this:
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
How to Export Templated Classes from a Dll Without Explicit Specification
Compiling with -Static-Libgcc -Static-Libstdc++ Still Results in Dynamic Dependency on Libc.So
Returning to Beginning of File After Getline
How to Access Private Data Members Outside the Class Without Making "Friend"S
Why Is a Char and a Bool the Same Size in C++
Why Doesn't Vector::Clear Remove Elements from a Vector
How to Get a Windows Symbol Server Set Up
Conditional Operator Used in Cout Statement
Boost::Flat_Map and Its Performance Compared to Map and Unordered_Map
How to Output the Value of an Enum Class in C++11
Embed Resources (Eg, Shader Code; Images) into Executable/Library with Cmake
What Destructors Are Run When the Constructor Throws an Exception
What Is the Underlying Type of a C++ Enum
Why Doesn't Std::String Provide Implicit Conversion to Char*